<!DOCTYPE html>
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
  <meta name="description" content="tong.li&#39;s blog">
  <meta name="keyword" content="彤哥哥博客，95后技术爱好者,现就职于同程旅行/同程艺龙上海分公司，专注于互联网技术分享的平台。">
  
    <link rel="shortcut icon" href="/css/images/icon.png">
  
  <title>
    
      深入分析HashMap源码 | 彤哥哥的博客
    
  </title>
  <link href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <link href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" rel="stylesheet">
  <link href="https://cdn.staticfile.org/highlight.js/9.12.0/styles/tomorrow-night.min.css" rel="stylesheet">
  
<link rel="stylesheet" href="/css/style.css">

  
  <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
  <script src="https://cdn.staticfile.org/geopattern/1.2.3/js/geopattern.min.js"></script>
  <script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js"></script>
  
    
<script src="/js/qrious.js"></script>

  
  
  
  
    <!-- MathJax support START -->
    <script type="text/x-mathjax-config">
      MathJax.Hub.Config({
        tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
          processEscapes: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
        }
      });
    </script>

    <script type="text/x-mathjax-config">
      MathJax.Hub.Queue(function() {
        var all = MathJax.Hub.getAllJax(), i;
        for (i=0; i < all.length; i += 1) {
          all[i].SourceElement().parentNode.className += ' has-jax';
        }
      });
    </script>
    <script type="text/javascript" src="https://cdn.staticfile.org/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
    <!-- MathJax support END -->
  


  
  
    
<script src="/js/local-search.js"></script>


<meta name="generator" content="Hexo 5.4.2"></head>
<div class="wechat-share">
  <img src="/css/images/logo.png" />
</div>
  <body>
    <header class="header fixed-header">
  <div class="header-container">
    <a class="home-link" href="/">
      <div class="logo"></div>
      <span>彤哥哥的博客</span>
    </a>
    <ul class="right-list">
      
        <li class="list-item">
          
            <a href="/" class="item-link">主页</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/series/" class="item-link">分类</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/tags/" class="item-link">标签</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/archives/" class="item-link">归档</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/project/" class="item-link">项目</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/about/" class="item-link">关于</a>
          
        </li>
      
      
        <li class="menu-item menu-item-search right-list">
    <a role="button" class="popup-trigger">
        <i class="fa fa-search fa-fw"></i>
    </a>
</li>
      
    </ul>
    <div class="menu">
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
    </div>
    <div class="menu-mask">
      <ul class="menu-list">
        
          <li class="menu-item">
            
              <a href="/" class="menu-link">主页</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/series/" class="menu-link">分类</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/tags/" class="menu-link">标签</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/archives/" class="menu-link">归档</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/project/" class="menu-link">项目</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/about/" class="menu-link">关于</a>
            
          </li>
        
      </ul>
    </div>
    
      <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
            <span class="search-icon">
                <i class="fa fa-search"></i>
            </span>
            <div class="search-input-container">
                <input autocomplete="off" autocapitalize="off"
                    placeholder="Please enter your keyword(s) to search." spellcheck="false"
                    type="search" class="search-input">
            </div>
            <span class="popup-btn-close">
                <i class="fa fa-times-circle"></i>
            </span>
        </div>
        <div id="search-result">
            <div id="no-result">
                <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
            </div>
        </div>
    </div>
</div>
    
  </div>
</header>

    <div id="article-banner">
  <h2>深入分析HashMap源码</h2>
  <p class="post-date">2020-06-18</p>
  <div class="arrow-down">
    <a href="javascript:;"></a>
  </div>
</div>
<main class="app-body flex-box">
  <!-- Article START -->
  <article class="post-article">
    <section class="markdown-content"><h1 id="1-HashMap简述"><a href="#1-HashMap简述" class="headerlink" title="1. HashMap简述"></a>1. HashMap简述</h1><h2 id="1-1-大致介绍"><a href="#1-1-大致介绍" class="headerlink" title="1.1 大致介绍"></a>1.1 大致介绍</h2><p>Map作为存放Key-Value数据容器在日常开发过程中是非常常见的，大部分的高级编程语言都具备Map类型的内存数据结构。在这里我们研究Java语言Map体系中最常用的HashMap(基于JDK1.8的实现)。</p>
<p>首先，我们打开HashMap源码找到类的文档注释，紧接着，我拿出二年级的英语水平以及谷歌翻译神器，大概翻译了一下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * HashMap是基于Map接口哈希表(Hash Table)的一种实现。</span></span><br><span class="line"><span class="comment"> * 此实现提供所有可选的映射(map)操作，并允许存放null值和null键。</span></span><br><span class="line"><span class="comment"> * (HashMap与Hashtable大致等效，但HashMap是不同步的，并且允许为null。)</span></span><br><span class="line"><span class="comment"> * 此类无法保证map的顺序。特别是，它不能保证顺序会随着时间的推移保持恒定(即存元素的顺序和取元素的顺序是不一致的)。</span></span><br><span class="line"><span class="comment"> * 假设哈希函数将元素恰好分散在存储桶中，则此实现为基本操作（get和put）提供恒定时间的性能。</span></span><br><span class="line"><span class="comment"> * 集合视图上的迭代所需的时间与HashMap实例的“容量(capacity)”（存储桶数）及其大小（键-值映射数）成正比。</span></span><br><span class="line"><span class="comment"> * 因此，如果迭代性能很重要，则不要将初始容量设置得过高（或负载因子过低），这一点非常重要。</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * HashMap的实例具有两个影响其性能的参数: 初始容量和负载因子</span></span><br><span class="line"><span class="comment"> * 容量是哈希表中的存储桶数，初始容量只是哈希表创建时的容量。</span></span><br><span class="line"><span class="comment"> * 负载因子是衡量散列表的容量在自动增加之前允许达到的满量。</span></span><br><span class="line"><span class="comment"> * 当哈希表中的entry(元素)数量超过负载因子和当前容量的乘积时，</span></span><br><span class="line"><span class="comment"> * 哈希表会rehashed(即内部数据结构被重建),以便哈希表的存储桶数量大约是其两倍。</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * 一般说来，默认的负载系数（.75）在时间和空间成本之间提供了一个很好的权衡。</span></span><br><span class="line"><span class="comment"> * 较高的值会减少空间开销，但会增加查找成本（体现在HashMap类的大多数操作中，包括get和put）。</span></span><br><span class="line"><span class="comment"> * 当设置map的初始容量时，应考虑map中预期的entry数量和负载因子，以便最大程度地减少重新哈希（rehash）操作的次数。</span></span><br><span class="line"><span class="comment"> * 如果初始容量大于最大entry数除以负载因子，则将不会进行任何哈希操作（反过来说，就是初始容量16*负载因子0.75 &lt; entry数量就需要扩容）。</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * 如果要在HashMap实例中存储许多映射，则创建具有足够大容量的映射将比让其根据需要增长表的自动重新哈希处理更有效地存储映射</span></span><br><span class="line"><span class="comment"> * （简言之，就是存许多映射时，指定足够大的容量可以避免反复自动rehash以提高程序性能）。</span></span><br><span class="line"><span class="comment"> * 请注意，使用许多具有相同hashCode()的键是降低任何哈希表性能的肯定方法。</span></span><br><span class="line"><span class="comment"> * 为了改善碰撞，当键为Comparable的实现类时，该类可以使用键之间的比较顺序来帮助打破关系。</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * 请注意，此实现不同步。如果多个线程同时并发访问一个hashmap，并且至少有一个线程在结构上修改了map，那么它必须在外部进行同步。</span></span><br><span class="line"><span class="comment"> * (结构修改是添加或删除一个或多个映射的任何操作。仅更改与实例已经包含的键相关联的值并不是结构上的修改。)</span></span><br><span class="line"><span class="comment"> * 这通常通过对自然地封装映射的一些对象(同步的map)进行同步来实现。这最好在创建时完成，以防止偶发的线程不同步访问map：</span></span><br><span class="line"><span class="comment"> * Map m = Collections.synchronizedMap(new HashMap(...));</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * 所有这个类的“集合视图方法”返回的迭代器都是fail-fast的：如果映射在迭代器创建之后的任何时间被结构地修改，</span></span><br><span class="line"><span class="comment"> * 除了通过迭代器自己的remove方法之外，迭代器将抛出一个ConcurrentModificationException。</span></span><br><span class="line"><span class="comment"> * 因此，面对并发修改，迭代器将快速而干净地失败，而不是在未来未确定的时间冒着任意的非确定性行为。</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * 请注意，迭代器的fail-fast行为无法保证，因为一般来说，在不同步并发修改的情况下，无法做出任何硬性保证。</span></span><br><span class="line"><span class="comment"> * fail-fast迭代器尽力最大努力抛出ConcurrentModificationException。</span></span><br><span class="line"><span class="comment"> * 因此，编写依赖于此异常的程序的正确性将是错误的：迭代器的fail-fast行为应仅用于检测错误。</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * 该类是Java Collections Framework的一员。</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &lt;K&gt; 存放Key键的类型</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &lt;V&gt; 存放Value值的类型</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>  Doug Lea</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>  Josh Bloch</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>  Arthur van Hoff</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>  Neal Gafter</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span>     Object#hashCode()</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span>     Collection</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span>     Map</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span>     TreeMap</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span>     Hashtable</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span>   1.2</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure>

<p>最后，我们通过对类注释的大致理解，就可以对HashMap有个初步的认识。</p>
<h2 id="1-2-底层数据结构"><a href="#1-2-底层数据结构" class="headerlink" title="1.2 底层数据结构"></a>1.2 底层数据结构</h2><ul>
<li>哈希表</li>
<li>链表</li>
<li>红黑树</li>
</ul>
<h2 id="1-3-继承体系"><a href="#1-3-继承体系" class="headerlink" title="1.3 继承体系"></a>1.3 继承体系</h2><p><img src="https://ltyeamin.github.io/imgs/2020/07/20200731161757.jpeg" alt="image-20200618154544604"></p>
<h3 id="1-3-1-Map顶层接口"><a href="#1-3-1-Map顶层接口" class="headerlink" title="1.3.1 Map顶层接口"></a>1.3.1 Map顶层接口</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br><span class="line">486</span><br><span class="line">487</span><br><span class="line">488</span><br><span class="line">489</span><br><span class="line">490</span><br><span class="line">491</span><br><span class="line">492</span><br><span class="line">493</span><br><span class="line">494</span><br><span class="line">495</span><br><span class="line">496</span><br><span class="line">497</span><br><span class="line">498</span><br><span class="line">499</span><br><span class="line">500</span><br><span class="line">501</span><br><span class="line">502</span><br><span class="line">503</span><br><span class="line">504</span><br><span class="line">505</span><br><span class="line">506</span><br><span class="line">507</span><br><span class="line">508</span><br><span class="line">509</span><br><span class="line">510</span><br><span class="line">511</span><br><span class="line">512</span><br><span class="line">513</span><br><span class="line">514</span><br><span class="line">515</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> java.util;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.function.BiConsumer;</span><br><span class="line"><span class="keyword">import</span> java.util.function.BiFunction;</span><br><span class="line"><span class="keyword">import</span> java.util.function.Function;</span><br><span class="line"><span class="keyword">import</span> java.io.Serializable;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Map的顶层接口</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &lt;K&gt;</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &lt;V&gt;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Map</span>&lt;K,V&gt; &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 查询操作</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 返回map中键值映射的数量。</span></span><br><span class="line"><span class="comment">     * 如果map包含超过Integer.MAX_VALUE个元素，则返回Integer.MAX_VALUE。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 此映射中的键值映射数</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="type">int</span> <span class="title function_">size</span><span class="params">()</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 如果map不包含键值映射，则返回true。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 如果此映射不包含键值映射返回true.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="type">boolean</span> <span class="title function_">isEmpty</span><span class="params">()</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 如果此映射包含指定key的映射，则返回true。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key 是否包含的key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 如果包含指定的key返回true</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="type">boolean</span> <span class="title function_">containsKey</span><span class="params">(Object key)</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 如果此映射包含指定value的映射，则返回true。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value 是否包含的value</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 如果包含指定的value返回true</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="type">boolean</span> <span class="title function_">containsValue</span><span class="params">(Object value)</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 返回到指定key所映射的value</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    V <span class="title function_">get</span><span class="params">(Object key)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 修改操作</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 将key和value存放到mao映射里</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    V <span class="title function_">put</span><span class="params">(K key, V value)</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 根据指定的key移除映射元素</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    V <span class="title function_">remove</span><span class="params">(Object key)</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 批量操作</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 将另一个map添加到当前map</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> m</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">putAll</span><span class="params">(Map&lt;? extends K, ? extends V&gt; m)</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 从map中清空所有的映射</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">clear</span><span class="params">()</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 视图</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 返回map中所有的key的Set集合(key不重复)</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    Set&lt;K&gt; <span class="title function_">keySet</span><span class="params">()</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 返回map中所有的value的Collection集合</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    Collection&lt;V&gt; <span class="title function_">values</span><span class="params">()</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 返回此map中包含的映射的Set集合</span></span><br><span class="line"><span class="comment">     * 集合元素的Entry对象是K-V映射关系</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    Set&lt;Entry&lt;K, V&gt;&gt; <span class="title function_">entrySet</span><span class="params">()</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 映射对象的抽象接口</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> &lt;K&gt;</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> &lt;V&gt;</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">interface</span> <span class="title class_">Entry</span>&lt;K,V&gt; &#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 返回当前entry对象的key</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        K <span class="title function_">getKey</span><span class="params">()</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 返回当前entry对象的value</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        V <span class="title function_">getValue</span><span class="params">()</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 修改当前entry对象的value</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> value</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        V <span class="title function_">setValue</span><span class="params">(V value)</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 比较两个entry是否相等</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> o</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">boolean</span> <span class="title function_">equals</span><span class="params">(Object o)</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 返回当前entry的哈希码值(hashcode)</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">int</span> <span class="title function_">hashCode</span><span class="params">()</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 返回一个Comparable比较器，根据Key的自然顺序来比较</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> &lt;K&gt;</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> &lt;V&gt;</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">static</span> &lt;K <span class="keyword">extends</span> <span class="title class_">Comparable</span>&lt;? <span class="built_in">super</span> K&gt;, V&gt; Comparator&lt;Map.Entry&lt;K,V&gt;&gt; comparingByKey() &#123;</span><br><span class="line">            <span class="keyword">return</span> (Comparator&lt;Map.Entry&lt;K, V&gt;&gt; &amp; Serializable)</span><br><span class="line">                    (c1, c2) -&gt; c1.getKey().compareTo(c2.getKey());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 返回一个Comparable比较器，根据Value的自然顺序来比较</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> &lt;K&gt;</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> &lt;V&gt;</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">static</span> &lt;K, V <span class="keyword">extends</span> <span class="title class_">Comparable</span>&lt;? <span class="built_in">super</span> V&gt;&gt; Comparator&lt;Map.Entry&lt;K,V&gt;&gt; comparingByValue() &#123;</span><br><span class="line">            <span class="keyword">return</span> (Comparator&lt;Map.Entry&lt;K, V&gt;&gt; &amp; Serializable)</span><br><span class="line">                    (c1, c2) -&gt; c1.getValue().compareTo(c2.getValue());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         *  返回一个Comparator比较器，根据Value的自然顺序来比较</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> cmp</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> &lt;K&gt;</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> &lt;V&gt;</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">static</span> &lt;K, V&gt; Comparator&lt;Map.Entry&lt;K, V&gt;&gt; comparingByKey(Comparator&lt;? <span class="built_in">super</span> K&gt; cmp) &#123;</span><br><span class="line">            Objects.requireNonNull(cmp);</span><br><span class="line">            <span class="keyword">return</span> (Comparator&lt;Map.Entry&lt;K, V&gt;&gt; &amp; Serializable)</span><br><span class="line">                    (c1, c2) -&gt; cmp.compare(c1.getKey(), c2.getKey());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 返回一个Comparable比较器，根据Value来的自然顺序来比较</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> &lt;K&gt;</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> &lt;V&gt;</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">static</span> &lt;K, V&gt; Comparator&lt;Map.Entry&lt;K, V&gt;&gt; comparingByValue(Comparator&lt;? <span class="built_in">super</span> V&gt; cmp) &#123;</span><br><span class="line">            Objects.requireNonNull(cmp);</span><br><span class="line">            <span class="keyword">return</span> (Comparator&lt;Map.Entry&lt;K, V&gt;&gt; &amp; Serializable)</span><br><span class="line">                    (c1, c2) -&gt; cmp.compare(c1.getValue(), c2.getValue());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 比较和哈希</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 比较指定对象与当前map是否相等</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> o</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="type">boolean</span> <span class="title function_">equals</span><span class="params">(Object o)</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 返回当前map的hashCode</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="type">int</span> <span class="title function_">hashCode</span><span class="params">()</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 默认方法实现</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 返回到指定Key所在映射的Value。</span></span><br><span class="line"><span class="comment">     * 如果找到了返回对应的value,若无此包含该键的映射则返回传参过来的默认值。</span></span><br><span class="line"><span class="comment">     * 默认实现不会保证此方法的同步或原子属性。 提供原子性保证的任何实现都必须覆盖此方法并记录其并发属性。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> defaultValue</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">default</span> V <span class="title function_">getOrDefault</span><span class="params">(Object key, V defaultValue)</span> &#123;</span><br><span class="line">        V v;</span><br><span class="line">        <span class="keyword">return</span> (((v = get(key)) != <span class="literal">null</span>) || containsKey(key))</span><br><span class="line">                ? v</span><br><span class="line">                : defaultValue;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 内部迭代执行指定的操作</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> action</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">default</span> <span class="keyword">void</span> <span class="title function_">forEach</span><span class="params">(BiConsumer&lt;? <span class="built_in">super</span> K, ? <span class="built_in">super</span> V&gt; action)</span> &#123;</span><br><span class="line">        <span class="comment">// 校验是否为空</span></span><br><span class="line">        Objects.requireNonNull(action);</span><br><span class="line">        <span class="comment">// 遍历</span></span><br><span class="line">        <span class="keyword">for</span> (Map.Entry&lt;K, V&gt; entry : entrySet()) &#123;</span><br><span class="line">            K k;</span><br><span class="line">            V v;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="comment">// 获取key</span></span><br><span class="line">                k = entry.getKey();</span><br><span class="line">                <span class="comment">// 获取value</span></span><br><span class="line">                v = entry.getValue();</span><br><span class="line">            &#125; <span class="keyword">catch</span>(IllegalStateException ise) &#123;</span><br><span class="line">                <span class="comment">// this usually means the entry is no longer in the map.</span></span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ConcurrentModificationException</span>(ise);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 执行操作</span></span><br><span class="line">            action.accept(k, v);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 循环遍历所有entry并将映射的value重新设置为function操作后的结果</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> function</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">default</span> <span class="keyword">void</span> <span class="title function_">replaceAll</span><span class="params">(BiFunction&lt;? <span class="built_in">super</span> K, ? <span class="built_in">super</span> V, ? extends V&gt; function)</span> &#123;</span><br><span class="line">        <span class="comment">// 校验操作是否为空对象</span></span><br><span class="line">        Objects.requireNonNull(function);</span><br><span class="line">        <span class="comment">// 循环遍历</span></span><br><span class="line">        <span class="keyword">for</span> (Map.Entry&lt;K, V&gt; entry : entrySet()) &#123;</span><br><span class="line">            K k;</span><br><span class="line">            V v;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="comment">// 获取key</span></span><br><span class="line">                k = entry.getKey();</span><br><span class="line">                <span class="comment">// 获取value</span></span><br><span class="line">                v = entry.getValue();</span><br><span class="line">            &#125; <span class="keyword">catch</span>(IllegalStateException ise) &#123;</span><br><span class="line">                <span class="comment">// this usually means the entry is no longer in the map.</span></span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ConcurrentModificationException</span>(ise);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 对key和vaue进行操作,这里可能抛出(IllegalStateException)而不是ConcurrentModificationException</span></span><br><span class="line">            <span class="comment">// ise thrown from function is not a cme.</span></span><br><span class="line">            v = function.apply(k, v);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="comment">// 重新set entry的value</span></span><br><span class="line">                entry.setValue(v);</span><br><span class="line">            &#125; <span class="keyword">catch</span>(IllegalStateException ise) &#123;</span><br><span class="line">                <span class="comment">// this usually means the entry is no longer in the map.</span></span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ConcurrentModificationException</span>(ise);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 典型的CAS操作。</span></span><br><span class="line"><span class="comment">     * 若存在key，则替换key对应的value。</span></span><br><span class="line"><span class="comment">     * 若不存在key,则将key和value添加到此map中。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">default</span> V <span class="title function_">putIfAbsent</span><span class="params">(K key, V value)</span> &#123;</span><br><span class="line">        <span class="comment">// 根据指定的key获取value</span></span><br><span class="line">        <span class="type">V</span> <span class="variable">v</span> <span class="operator">=</span> get(key);</span><br><span class="line">        <span class="comment">// 如果返回的value为null,将key和value添加到map中</span></span><br><span class="line">        <span class="keyword">if</span> (v == <span class="literal">null</span>) &#123;</span><br><span class="line">            v = put(key, value);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 返回value</span></span><br><span class="line">        <span class="keyword">return</span> v;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     *  根据key和value校验后删除指定的映射关系</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">default</span> <span class="type">boolean</span> <span class="title function_">remove</span><span class="params">(Object key, Object value)</span> &#123;</span><br><span class="line">        <span class="comment">// 根据key获取当前的value</span></span><br><span class="line">        <span class="type">Object</span> <span class="variable">curValue</span> <span class="operator">=</span> get(key);</span><br><span class="line">        <span class="comment">// 如果当前的value和传入的value不同或者当前value为空且对应的key不在map映射中，直接返回false</span></span><br><span class="line">        <span class="keyword">if</span> (!Objects.equals(curValue, value) ||</span><br><span class="line">                (curValue == <span class="literal">null</span> &amp;&amp; !containsKey(key))) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 删除指定的映射</span></span><br><span class="line">        remove(key);</span><br><span class="line">        <span class="comment">// 删除后返true</span></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * key、oldValue校验成功后替换key的最新value为newValue</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> oldValue</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> newValue</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">default</span> <span class="type">boolean</span> <span class="title function_">replace</span><span class="params">(K key, V oldValue, V newValue)</span> &#123;</span><br><span class="line">        <span class="comment">// 获取当前key对应的value</span></span><br><span class="line">        <span class="type">Object</span> <span class="variable">curValue</span> <span class="operator">=</span> get(key);</span><br><span class="line">        <span class="comment">// 如果当前的value和传入的value不同或者当前value为空且对应的key不在map映射中，直接返回false</span></span><br><span class="line">        <span class="keyword">if</span> (!Objects.equals(curValue, oldValue) ||</span><br><span class="line">                (curValue == <span class="literal">null</span> &amp;&amp; !containsKey(key))) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 将key对应的value覆盖为最新的newValue</span></span><br><span class="line">        put(key, newValue);</span><br><span class="line">        <span class="comment">// 返回true</span></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 替换key对应的oldValue为最新value，并返回oldValue</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">default</span> V <span class="title function_">replace</span><span class="params">(K key, V value)</span> &#123;</span><br><span class="line">        <span class="comment">// 存放当前map中key对应的value</span></span><br><span class="line">        V curValue;</span><br><span class="line">        <span class="comment">// 如果key对应的value存在</span></span><br><span class="line">        <span class="keyword">if</span> (((curValue = get(key)) != <span class="literal">null</span>) || containsKey(key)) &#123;</span><br><span class="line">            <span class="comment">// 重新替换key的curValue为value</span></span><br><span class="line">            curValue = put(key, value);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 返回替换之前的value</span></span><br><span class="line">        <span class="keyword">return</span> curValue;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 对于存在的指定key的value映射，不做任何操作，直接返回value。</span></span><br><span class="line"><span class="comment">     * 对于不存在的指定key的value映射,通过mappingFunction操作后，将操作结果作为key的value存入map中。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> mappingFunction</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">default</span> V <span class="title function_">computeIfAbsent</span><span class="params">(K key,</span></span><br><span class="line"><span class="params">                              Function&lt;? <span class="built_in">super</span> K, ? extends V&gt; mappingFunction)</span> &#123;</span><br><span class="line">        <span class="comment">// 校验mappingFunction操作对象是否为null</span></span><br><span class="line">        Objects.requireNonNull(mappingFunction);</span><br><span class="line">        <span class="comment">// 存放value</span></span><br><span class="line">        V v;</span><br><span class="line">        <span class="comment">// 判断value等于null</span></span><br><span class="line">        <span class="keyword">if</span> ((v = get(key)) == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 存放新的value</span></span><br><span class="line">            V newValue;</span><br><span class="line">            <span class="comment">// 对于key进行mappingFunction操作，并把操作结果赋值给newValue</span></span><br><span class="line">            <span class="keyword">if</span> ((newValue = mappingFunction.apply(key)) != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="comment">// 如果newValue不是null，替换key之前的value</span></span><br><span class="line">                put(key, newValue);</span><br><span class="line">                <span class="comment">// 返回newValue</span></span><br><span class="line">                <span class="keyword">return</span> newValue;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 如果value不等于不做任何操作</span></span><br><span class="line">        <span class="keyword">return</span> v;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 对于存在的指定key的value映射，通过remappingFunction操作后，将操作结果作为key的newValue存入map中并返回newValue。</span></span><br><span class="line"><span class="comment">     * 对于不存在的指定key的value映射，不做任何操作，直接返回null。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> remappingFunction</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">default</span> V <span class="title function_">computeIfPresent</span><span class="params">(K key,</span></span><br><span class="line"><span class="params">                               BiFunction&lt;? <span class="built_in">super</span> K, ? <span class="built_in">super</span> V, ? extends V&gt; remappingFunction)</span> &#123;</span><br><span class="line">        <span class="comment">// 校验remappingFunction操作对象是否为null</span></span><br><span class="line">        Objects.requireNonNull(remappingFunction);</span><br><span class="line">        <span class="comment">// 存放旧值value</span></span><br><span class="line">        V oldValue;</span><br><span class="line">        <span class="comment">// 如果旧值oldValue不等于null,做remappingFunction操作返回newValue</span></span><br><span class="line">        <span class="keyword">if</span> ((oldValue = get(key)) != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="type">V</span> <span class="variable">newValue</span> <span class="operator">=</span> remappingFunction.apply(key, oldValue);</span><br><span class="line">            <span class="keyword">if</span> (newValue != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="comment">// 如果newValue不为null，替换oldValue为newValue</span></span><br><span class="line">                put(key, newValue);</span><br><span class="line">                <span class="comment">// 返回newValue</span></span><br><span class="line">                <span class="keyword">return</span> newValue;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="comment">// 如果newValue为null，移除key的映射</span></span><br><span class="line">                remove(key);</span><br><span class="line">                <span class="comment">// 返回null</span></span><br><span class="line">                <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 如果旧值oldValue等于null,返回null</span></span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * 做一些remappingFunction后的结果作为key的value</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> remappingFunction</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">default</span> V <span class="title function_">compute</span><span class="params">(K key,</span></span><br><span class="line"><span class="params">                      BiFunction&lt;? <span class="built_in">super</span> K, ? <span class="built_in">super</span> V, ? extends V&gt; remappingFunction)</span> &#123;</span><br><span class="line">        <span class="comment">// 校验remappingFunction操作对象是否为null</span></span><br><span class="line">        Objects.requireNonNull(remappingFunction);</span><br><span class="line">        <span class="comment">// 获取key的旧值oldValue</span></span><br><span class="line">        <span class="type">V</span> <span class="variable">oldValue</span> <span class="operator">=</span> get(key);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 做一些remappingFunction操作，获取newValue</span></span><br><span class="line">        <span class="type">V</span> <span class="variable">newValue</span> <span class="operator">=</span> remappingFunction.apply(key, oldValue);</span><br><span class="line">        <span class="comment">// 如果操作后的newValue为null</span></span><br><span class="line">        <span class="keyword">if</span> (newValue == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 删除映射关系</span></span><br><span class="line">            <span class="keyword">if</span> (oldValue != <span class="literal">null</span> || containsKey(key)) &#123;</span><br><span class="line">                <span class="comment">// 如果oldValue不为null或包含此key的映射关系，删除这个key的映射</span></span><br><span class="line">                remove(key);</span><br><span class="line">                <span class="comment">// 删除成功后，返回null</span></span><br><span class="line">                <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="comment">// 如果newValue不为null,什么也不做，直接返回null</span></span><br><span class="line">                <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 添加或替换旧的映射</span></span><br><span class="line">            put(key, newValue);</span><br><span class="line">            <span class="comment">// 返回新的newValue</span></span><br><span class="line">            <span class="keyword">return</span> newValue;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 做一些remappingFunction后的结果作为key的value</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> remappingFunction</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">default</span> V <span class="title function_">merge</span><span class="params">(K key, V value,</span></span><br><span class="line"><span class="params">                    BiFunction&lt;? <span class="built_in">super</span> V, ? <span class="built_in">super</span> V, ? extends V&gt; remappingFunction)</span> &#123;</span><br><span class="line">        <span class="comment">// 校验remappingFunction操作对象是否为null</span></span><br><span class="line">        Objects.requireNonNull(remappingFunction);</span><br><span class="line">        <span class="comment">// 校验value操作对象是否为null</span></span><br><span class="line">        Objects.requireNonNull(value);</span><br><span class="line">        <span class="comment">// 获取key的旧值oldValue</span></span><br><span class="line">        <span class="type">V</span> <span class="variable">oldValue</span> <span class="operator">=</span> get(key);</span><br><span class="line">        <span class="comment">// 根据oldValue判断获取新的newValue</span></span><br><span class="line">        <span class="type">V</span> <span class="variable">newValue</span> <span class="operator">=</span> (oldValue == <span class="literal">null</span>) ? value :</span><br><span class="line">                remappingFunction.apply(oldValue, value);</span><br><span class="line">        <span class="keyword">if</span>(newValue == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 如果newValue为空，remove掉</span></span><br><span class="line">            remove(key);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 重新将key的value set为newValue</span></span><br><span class="line">            put(key, newValue);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 返回newValue</span></span><br><span class="line">        <span class="keyword">return</span> newValue;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="1-3-2-AbstractMap抽象类"><a href="#1-3-2-AbstractMap抽象类" class="headerlink" title="1.3.2 AbstractMap抽象类"></a>1.3.2 AbstractMap抽象类</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br><span class="line">486</span><br><span class="line">487</span><br><span class="line">488</span><br><span class="line">489</span><br><span class="line">490</span><br><span class="line">491</span><br><span class="line">492</span><br><span class="line">493</span><br><span class="line">494</span><br><span class="line">495</span><br><span class="line">496</span><br><span class="line">497</span><br><span class="line">498</span><br><span class="line">499</span><br><span class="line">500</span><br><span class="line">501</span><br><span class="line">502</span><br><span class="line">503</span><br><span class="line">504</span><br><span class="line">505</span><br><span class="line">506</span><br><span class="line">507</span><br><span class="line">508</span><br><span class="line">509</span><br><span class="line">510</span><br><span class="line">511</span><br><span class="line">512</span><br><span class="line">513</span><br><span class="line">514</span><br><span class="line">515</span><br><span class="line">516</span><br><span class="line">517</span><br><span class="line">518</span><br><span class="line">519</span><br><span class="line">520</span><br><span class="line">521</span><br><span class="line">522</span><br><span class="line">523</span><br><span class="line">524</span><br><span class="line">525</span><br><span class="line">526</span><br><span class="line">527</span><br><span class="line">528</span><br><span class="line">529</span><br><span class="line">530</span><br><span class="line">531</span><br><span class="line">532</span><br><span class="line">533</span><br><span class="line">534</span><br><span class="line">535</span><br><span class="line">536</span><br><span class="line">537</span><br><span class="line">538</span><br><span class="line">539</span><br><span class="line">540</span><br><span class="line">541</span><br><span class="line">542</span><br><span class="line">543</span><br><span class="line">544</span><br><span class="line">545</span><br><span class="line">546</span><br><span class="line">547</span><br><span class="line">548</span><br><span class="line">549</span><br><span class="line">550</span><br><span class="line">551</span><br><span class="line">552</span><br><span class="line">553</span><br><span class="line">554</span><br><span class="line">555</span><br><span class="line">556</span><br><span class="line">557</span><br><span class="line">558</span><br><span class="line">559</span><br><span class="line">560</span><br><span class="line">561</span><br><span class="line">562</span><br><span class="line">563</span><br><span class="line">564</span><br><span class="line">565</span><br><span class="line">566</span><br><span class="line">567</span><br><span class="line">568</span><br><span class="line">569</span><br><span class="line">570</span><br><span class="line">571</span><br><span class="line">572</span><br><span class="line">573</span><br><span class="line">574</span><br><span class="line">575</span><br><span class="line">576</span><br><span class="line">577</span><br><span class="line">578</span><br><span class="line">579</span><br><span class="line">580</span><br><span class="line">581</span><br><span class="line">582</span><br><span class="line">583</span><br><span class="line">584</span><br><span class="line">585</span><br><span class="line">586</span><br><span class="line">587</span><br><span class="line">588</span><br><span class="line">589</span><br><span class="line">590</span><br><span class="line">591</span><br><span class="line">592</span><br><span class="line">593</span><br><span class="line">594</span><br><span class="line">595</span><br><span class="line">596</span><br><span class="line">597</span><br><span class="line">598</span><br><span class="line">599</span><br><span class="line">600</span><br><span class="line">601</span><br><span class="line">602</span><br><span class="line">603</span><br><span class="line">604</span><br><span class="line">605</span><br><span class="line">606</span><br><span class="line">607</span><br><span class="line">608</span><br><span class="line">609</span><br><span class="line">610</span><br><span class="line">611</span><br><span class="line">612</span><br><span class="line">613</span><br><span class="line">614</span><br><span class="line">615</span><br><span class="line">616</span><br><span class="line">617</span><br><span class="line">618</span><br><span class="line">619</span><br><span class="line">620</span><br><span class="line">621</span><br><span class="line">622</span><br><span class="line">623</span><br><span class="line">624</span><br><span class="line">625</span><br><span class="line">626</span><br><span class="line">627</span><br><span class="line">628</span><br><span class="line">629</span><br><span class="line">630</span><br><span class="line">631</span><br><span class="line">632</span><br><span class="line">633</span><br><span class="line">634</span><br><span class="line">635</span><br><span class="line">636</span><br><span class="line">637</span><br><span class="line">638</span><br><span class="line">639</span><br><span class="line">640</span><br><span class="line">641</span><br><span class="line">642</span><br><span class="line">643</span><br><span class="line">644</span><br><span class="line">645</span><br><span class="line">646</span><br><span class="line">647</span><br><span class="line">648</span><br><span class="line">649</span><br><span class="line">650</span><br><span class="line">651</span><br><span class="line">652</span><br><span class="line">653</span><br><span class="line">654</span><br><span class="line">655</span><br><span class="line">656</span><br><span class="line">657</span><br><span class="line">658</span><br><span class="line">659</span><br><span class="line">660</span><br><span class="line">661</span><br><span class="line">662</span><br><span class="line">663</span><br><span class="line">664</span><br><span class="line">665</span><br><span class="line">666</span><br><span class="line">667</span><br><span class="line">668</span><br><span class="line">669</span><br><span class="line">670</span><br><span class="line">671</span><br><span class="line">672</span><br><span class="line">673</span><br><span class="line">674</span><br><span class="line">675</span><br><span class="line">676</span><br><span class="line">677</span><br><span class="line">678</span><br><span class="line">679</span><br><span class="line">680</span><br><span class="line">681</span><br><span class="line">682</span><br><span class="line">683</span><br><span class="line">684</span><br><span class="line">685</span><br><span class="line">686</span><br><span class="line">687</span><br><span class="line">688</span><br><span class="line">689</span><br><span class="line">690</span><br><span class="line">691</span><br><span class="line">692</span><br><span class="line">693</span><br><span class="line">694</span><br><span class="line">695</span><br><span class="line">696</span><br><span class="line">697</span><br><span class="line">698</span><br><span class="line">699</span><br><span class="line">700</span><br><span class="line">701</span><br><span class="line">702</span><br><span class="line">703</span><br><span class="line">704</span><br><span class="line">705</span><br><span class="line">706</span><br><span class="line">707</span><br><span class="line">708</span><br><span class="line">709</span><br><span class="line">710</span><br><span class="line">711</span><br><span class="line">712</span><br><span class="line">713</span><br><span class="line">714</span><br><span class="line">715</span><br><span class="line">716</span><br><span class="line">717</span><br><span class="line">718</span><br><span class="line">719</span><br><span class="line">720</span><br><span class="line">721</span><br><span class="line">722</span><br><span class="line">723</span><br><span class="line">724</span><br><span class="line">725</span><br><span class="line">726</span><br><span class="line">727</span><br><span class="line">728</span><br><span class="line">729</span><br><span class="line">730</span><br><span class="line">731</span><br><span class="line">732</span><br><span class="line">733</span><br><span class="line">734</span><br><span class="line">735</span><br><span class="line">736</span><br><span class="line">737</span><br><span class="line">738</span><br><span class="line">739</span><br><span class="line">740</span><br><span class="line">741</span><br><span class="line">742</span><br><span class="line">743</span><br><span class="line">744</span><br><span class="line">745</span><br><span class="line">746</span><br><span class="line">747</span><br><span class="line">748</span><br><span class="line">749</span><br><span class="line">750</span><br><span class="line">751</span><br><span class="line">752</span><br><span class="line">753</span><br><span class="line">754</span><br><span class="line">755</span><br><span class="line">756</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> java.util;</span><br><span class="line"><span class="keyword">import</span> java.util.Map.Entry;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 抽象的Map,实现的map的基本功能</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &lt;K&gt;</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &lt;V&gt;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">AbstractMap</span>&lt;K,V&gt; <span class="keyword">implements</span> <span class="title class_">Map</span>&lt;K,V&gt; &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 唯一的构造器，通常是子类隐式调用</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="title function_">AbstractMap</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 查询操作</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 此实现返回entrySet().size()。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">size</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> entrySet().size();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 此实现返回size() == 0比较的结果。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isEmpty</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> size() == <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 如果此映射包含指定value的映射，则返回true，否则返回false</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value 是否包含的value</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">containsValue</span><span class="params">(Object value)</span> &#123;</span><br><span class="line">        <span class="comment">// 获取entrySet()的迭代器对象</span></span><br><span class="line">        Iterator&lt;Entry&lt;K,V&gt;&gt; i = entrySet().iterator();</span><br><span class="line">        <span class="comment">// 判断value是否null</span></span><br><span class="line">        <span class="keyword">if</span> (value==<span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 如何value为null,迭代遍历获取元素</span></span><br><span class="line">            <span class="comment">// i.hasNext()判断迭代器是否还有下一个元素</span></span><br><span class="line">            <span class="keyword">while</span> (i.hasNext()) &#123;</span><br><span class="line">                <span class="comment">// 获取当前迭代的元素</span></span><br><span class="line">                Entry&lt;K,V&gt; e = i.next();</span><br><span class="line">                <span class="comment">// 如果真的有null值的value,直接返回true</span></span><br><span class="line">                <span class="keyword">if</span> (e.getValue()==<span class="literal">null</span>)</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 如果value不为null，也循环遍历</span></span><br><span class="line">            <span class="keyword">while</span> (i.hasNext()) &#123;</span><br><span class="line">                <span class="comment">// 获取当前迭代的元素</span></span><br><span class="line">                Entry&lt;K,V&gt; e = i.next();</span><br><span class="line">                <span class="comment">// 这里也是比对，只不过两个对象(value)比对用equals，相同则返回true</span></span><br><span class="line">                <span class="keyword">if</span> (value.equals(e.getValue()))</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 上述情况都不存在，即在找不到这个value，直接返回false</span></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 如果此映射包含指定key的映射，则返回true，否则返回false</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key 是否包含的key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">containsKey</span><span class="params">(Object key)</span> &#123;</span><br><span class="line">        <span class="comment">// 获取entrySet()的迭代器对象</span></span><br><span class="line">        Iterator&lt;Map.Entry&lt;K,V&gt;&gt; i = entrySet().iterator();</span><br><span class="line">        <span class="comment">// 判断key是否null</span></span><br><span class="line">        <span class="keyword">if</span> (key==<span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 如何key为null,迭代遍历获取元素</span></span><br><span class="line">            <span class="keyword">while</span> (i.hasNext()) &#123;</span><br><span class="line">                <span class="comment">// 获取当前迭代的元素</span></span><br><span class="line">                Entry&lt;K,V&gt; e = i.next();</span><br><span class="line">                <span class="comment">// 如果真的有null值的键,直接返回true</span></span><br><span class="line">                <span class="keyword">if</span> (e.getKey()==<span class="literal">null</span>)</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 如何key不为null,迭代遍历获取元素</span></span><br><span class="line">            <span class="keyword">while</span> (i.hasNext()) &#123;</span><br><span class="line">                <span class="comment">// 获取当前迭代的元素</span></span><br><span class="line">                Entry&lt;K,V&gt; e = i.next();</span><br><span class="line">                <span class="comment">// 这里也是比对，只不过两个对象(value)比对用equals，相同则返回true</span></span><br><span class="line">                <span class="keyword">if</span> (key.equals(e.getKey()))</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 上述情况都不存在，即在找不到这个key，直接返回false</span></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 根据key获取value</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> V <span class="title function_">get</span><span class="params">(Object key)</span> &#123;</span><br><span class="line">        <span class="comment">// 获取entrySet()的迭代器对象</span></span><br><span class="line">        Iterator&lt;Entry&lt;K,V&gt;&gt; i = entrySet().iterator();</span><br><span class="line">        <span class="comment">// 处理空键: 如果key为null值,迭代遍历取出映射entry对象,直接返回entry的value</span></span><br><span class="line">        <span class="keyword">if</span> (key==<span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">while</span> (i.hasNext()) &#123;</span><br><span class="line">                Entry&lt;K,V&gt; e = i.next();</span><br><span class="line">                <span class="keyword">if</span> (e.getKey()==<span class="literal">null</span>)</span><br><span class="line">                    <span class="keyword">return</span> e.getValue();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 处理非空键: 如果key不为null值,迭代遍历取出映射entry对象,直接返回entry的value</span></span><br><span class="line">            <span class="keyword">while</span> (i.hasNext()) &#123;</span><br><span class="line">                Entry&lt;K,V&gt; e = i.next();</span><br><span class="line">                <span class="keyword">if</span> (key.equals(e.getKey()))</span><br><span class="line">                    <span class="keyword">return</span> e.getValue();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 上述两种情况都未找到key的映射，直接返回null</span></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 修改操作</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 这个抽象类的put方法不允许外部调用，一旦外部调用抛出UnsupportedOperationException</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> V <span class="title function_">put</span><span class="params">(K key, V value)</span> &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UnsupportedOperationException</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 根据key移除对应的映射元素</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> V <span class="title function_">remove</span><span class="params">(Object key)</span> &#123;</span><br><span class="line">        <span class="comment">// 获取entrySet()的迭代器对象</span></span><br><span class="line">        Iterator&lt;Entry&lt;K,V&gt;&gt; i = entrySet().iterator();</span><br><span class="line">        <span class="comment">// 声明一个Entry对象,用于存放key对应的映射entry</span></span><br><span class="line">        Entry&lt;K,V&gt; correctEntry = <span class="literal">null</span>;</span><br><span class="line">        <span class="comment">// 判断key是否为null</span></span><br><span class="line">        <span class="keyword">if</span> (key==<span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 空键处理: 迭代遍历,知道找到key对应的Entry对应，若找到赋值给correctEntry变量</span></span><br><span class="line">            <span class="keyword">while</span> (correctEntry==<span class="literal">null</span> &amp;&amp; i.hasNext()) &#123;</span><br><span class="line">                Entry&lt;K,V&gt; e = i.next();</span><br><span class="line">                <span class="keyword">if</span> (e.getKey()==<span class="literal">null</span>)</span><br><span class="line">                    correctEntry = e;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 非空键处理: 迭代遍历,直到找到key对应的Entry对应，若找到赋值给correctEntry变量</span></span><br><span class="line">            <span class="keyword">while</span> (correctEntry==<span class="literal">null</span> &amp;&amp; i.hasNext()) &#123;</span><br><span class="line">                Entry&lt;K,V&gt; e = i.next();</span><br><span class="line">                <span class="keyword">if</span> (key.equals(e.getKey()))</span><br><span class="line">                    correctEntry = e;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 声明一个变量，存放key对应的旧值oldValue</span></span><br><span class="line">        <span class="type">V</span> <span class="variable">oldValue</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">        <span class="comment">// 判断上述的查找操作correctEntry是否找到，即判断是否为null</span></span><br><span class="line">        <span class="keyword">if</span> (correctEntry !=<span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 如果correctEntry找到了,获取value并赋值给oldValue</span></span><br><span class="line">            oldValue = correctEntry.getValue();</span><br><span class="line">            <span class="comment">// 删除当前指针所指向的元素，找到correctEntry，光标指针会停留在correctEntry，所以不用传参删除</span></span><br><span class="line">            i.remove();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 返回旧值oldValue</span></span><br><span class="line">        <span class="keyword">return</span> oldValue;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 批量操作</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 将一个map映射m添加到当前map映射中</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> m</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">putAll</span><span class="params">(Map&lt;? extends K, ? extends V&gt; m)</span> &#123;</span><br><span class="line">        <span class="comment">// 迭代遍历,将m所有的映射存放在当前映射里</span></span><br><span class="line">        <span class="keyword">for</span> (Map.Entry&lt;? <span class="keyword">extends</span> <span class="title class_">K</span>, ? <span class="keyword">extends</span> <span class="title class_">V</span>&gt; e : m.entrySet())</span><br><span class="line">            put(e.getKey(), e.getValue());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 清空map中所有的映射</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">clear</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">// 其实就是调用Set集合的clear()</span></span><br><span class="line">        entrySet().clear();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 视图</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * map映射中所有(不重复)键视图(Set)集合</span></span><br><span class="line"><span class="comment">     * transient修饰的字段将不会序列化</span></span><br><span class="line"><span class="comment">     * 此字段可能是线程不安全的</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">transient</span> Set&lt;K&gt;        keySet;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * map映射中所有值视图(Collection)集合</span></span><br><span class="line"><span class="comment">     * transient修饰的字段将不会序列化</span></span><br><span class="line"><span class="comment">     * 此字段可能是线程不安全的</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">transient</span> Collection&lt;V&gt; values;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取map映射中所有(不重复)键视图(Set)集合</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> Set&lt;K&gt; <span class="title function_">keySet</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">// 将keySet赋值给ks</span></span><br><span class="line">        Set&lt;K&gt; ks = keySet;</span><br><span class="line">        <span class="comment">// 判断ks是否为null</span></span><br><span class="line">        <span class="keyword">if</span> (ks == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 若ks为null,实现一个AbstractSet的匿名内部类,并new出来赋值给ks</span></span><br><span class="line">            ks = <span class="keyword">new</span> <span class="title class_">AbstractSet</span>&lt;K&gt;() &#123;</span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="keyword">public</span> Iterator&lt;K&gt; <span class="title function_">iterator</span><span class="params">()</span> &#123;</span><br><span class="line">                    <span class="comment">// 这里默认也实现一个AbstractSet.Iterator的匿名内部类</span></span><br><span class="line">                    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Iterator</span>&lt;K&gt;() &#123;</span><br><span class="line">                        <span class="comment">// 获取entrySet()的迭代器对象</span></span><br><span class="line">                        <span class="keyword">private</span> Iterator&lt;Map.Entry&lt;K,V&gt;&gt; i = entrySet().iterator();</span><br><span class="line"></span><br><span class="line">                        <span class="comment">/**</span></span><br><span class="line"><span class="comment">                         * 光标后移,判断是否有元素，即使判断是否有下一个元素</span></span><br><span class="line"><span class="comment">                         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">                         */</span></span><br><span class="line">                        <span class="meta">@Override</span></span><br><span class="line">                        <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">hasNext</span><span class="params">()</span> &#123;</span><br><span class="line">                            <span class="keyword">return</span> i.hasNext();</span><br><span class="line">                        &#125;</span><br><span class="line"></span><br><span class="line">                        <span class="comment">/**</span></span><br><span class="line"><span class="comment">                         * 获取当前光标的元素(这里返回的是entry的key)</span></span><br><span class="line"><span class="comment">                         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">                         */</span></span><br><span class="line">                        <span class="meta">@Override</span></span><br><span class="line">                        <span class="keyword">public</span> K <span class="title function_">next</span><span class="params">()</span> &#123;</span><br><span class="line">                            <span class="keyword">return</span> i.next().getKey();</span><br><span class="line">                        &#125;</span><br><span class="line"></span><br><span class="line">                        <span class="comment">/**</span></span><br><span class="line"><span class="comment">                         * 移除当前光标的元素</span></span><br><span class="line"><span class="comment">                         */</span></span><br><span class="line">                        <span class="meta">@Override</span></span><br><span class="line">                        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">remove</span><span class="params">()</span> &#123;</span><br><span class="line">                            i.remove();</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="comment">/**</span></span><br><span class="line"><span class="comment">                 * 返回迭代器的大小</span></span><br><span class="line"><span class="comment">                 * 迭代器的size()实现应当与AbstractMap.this.size()一致</span></span><br><span class="line"><span class="comment">                 * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">                 */</span></span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">size</span><span class="params">()</span> &#123;</span><br><span class="line">                    <span class="keyword">return</span> AbstractMap.<span class="built_in">this</span>.size();</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="comment">/**</span></span><br><span class="line"><span class="comment">                 * 判断迭代器是否有元素,无元素返回false。</span></span><br><span class="line"><span class="comment">                 * 迭代器的isEmpty()实现应当与AbstractMap.this.isEmpty()一致</span></span><br><span class="line"><span class="comment">                 * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">                 */</span></span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isEmpty</span><span class="params">()</span> &#123;</span><br><span class="line">                    <span class="keyword">return</span> AbstractMap.<span class="built_in">this</span>.isEmpty();</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="comment">/**</span></span><br><span class="line"><span class="comment">                 * 清空迭代器的元素</span></span><br><span class="line"><span class="comment">                 * 迭代器的clear()实现应当与AbstractMap.this.clear()一致</span></span><br><span class="line"><span class="comment">                 * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">                 */</span></span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">clear</span><span class="params">()</span> &#123;</span><br><span class="line">                    AbstractMap.<span class="built_in">this</span>.clear();</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="comment">/**</span></span><br><span class="line"><span class="comment">                 * 判断迭代器是否包含元素k。</span></span><br><span class="line"><span class="comment">                 * 迭代器的contains()实现应当与AbstractMap.this.contains()一致</span></span><br><span class="line"><span class="comment">                 * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">                 */</span></span><br><span class="line">                <span class="meta">@Override</span></span><br><span class="line">                <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">contains</span><span class="params">(Object k)</span> &#123;</span><br><span class="line">                    <span class="keyword">return</span> AbstractMap.<span class="built_in">this</span>.containsKey(k);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;;</span><br><span class="line">            <span class="comment">// 然后将一个实现的匿名类赋值给全局的keySet视图，第一次初始化视图</span></span><br><span class="line">            keySet = ks;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 直接返回ks</span></span><br><span class="line">        <span class="keyword">return</span> ks;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取map映射中所有值视图(Collection)集合</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> Collection&lt;V&gt; <span class="title function_">values</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">// 将values赋值给ks</span></span><br><span class="line">        Collection&lt;V&gt; vals = values;</span><br><span class="line">        <span class="comment">// 判断vals是否为null</span></span><br><span class="line">        <span class="keyword">if</span> (vals == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 若vals为null,实现一个AbstractCollection的匿名内部类,并new出来赋值给vals</span></span><br><span class="line">            vals = <span class="keyword">new</span> <span class="title class_">AbstractCollection</span>&lt;V&gt;() &#123;</span><br><span class="line">                <span class="comment">// 这里默认也实现一个AbstractCollection.Iterator的匿名内部类</span></span><br><span class="line">                <span class="keyword">public</span> Iterator&lt;V&gt; <span class="title function_">iterator</span><span class="params">()</span> &#123;</span><br><span class="line"></span><br><span class="line">                    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Iterator</span>&lt;V&gt;() &#123;</span><br><span class="line">                        <span class="comment">// 获取entrySet()的迭代器对象</span></span><br><span class="line">                        <span class="keyword">private</span> Iterator&lt;Entry&lt;K,V&gt;&gt; i = entrySet().iterator();</span><br><span class="line"></span><br><span class="line">                        <span class="comment">/**</span></span><br><span class="line"><span class="comment">                         * 光标后移,判断是否有元素，即使判断是否有下一个元素</span></span><br><span class="line"><span class="comment">                         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">                         */</span></span><br><span class="line">                        <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">hasNext</span><span class="params">()</span> &#123;</span><br><span class="line">                            <span class="keyword">return</span> i.hasNext();</span><br><span class="line">                        &#125;</span><br><span class="line"></span><br><span class="line">                        <span class="comment">/**</span></span><br><span class="line"><span class="comment">                         * 获取当前光标的元素对应的元素(这里返回的是entry的key)</span></span><br><span class="line"><span class="comment">                         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">                         */</span></span><br><span class="line">                        <span class="keyword">public</span> V <span class="title function_">next</span><span class="params">()</span> &#123;</span><br><span class="line">                            <span class="keyword">return</span> i.next().getValue();</span><br><span class="line">                        &#125;</span><br><span class="line"></span><br><span class="line">                        <span class="comment">/**</span></span><br><span class="line"><span class="comment">                         * 移除当前光标的元素</span></span><br><span class="line"><span class="comment">                         */</span></span><br><span class="line">                        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">remove</span><span class="params">()</span> &#123;</span><br><span class="line">                            i.remove();</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="comment">/**</span></span><br><span class="line"><span class="comment">                 * 返回迭代器的大小</span></span><br><span class="line"><span class="comment">                 * 迭代器的size()实现应当与AbstractMap.this.size()一致</span></span><br><span class="line"><span class="comment">                 * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">                 */</span></span><br><span class="line">                <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">size</span><span class="params">()</span> &#123;</span><br><span class="line">                    <span class="keyword">return</span> AbstractMap.<span class="built_in">this</span>.size();</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="comment">/**</span></span><br><span class="line"><span class="comment">                 * 判断迭代器是否有元素,无元素返回false。</span></span><br><span class="line"><span class="comment">                 * 迭代器的isEmpty()实现应当与AbstractMap.this.isEmpty()一致</span></span><br><span class="line"><span class="comment">                 * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">                 */</span></span><br><span class="line">                <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isEmpty</span><span class="params">()</span> &#123;</span><br><span class="line">                    <span class="keyword">return</span> AbstractMap.<span class="built_in">this</span>.isEmpty();</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="comment">/**</span></span><br><span class="line"><span class="comment">                 * 清空迭代器的元素</span></span><br><span class="line"><span class="comment">                 * 迭代器的clear()实现应当与AbstractMap.this.clear()一致</span></span><br><span class="line"><span class="comment">                 * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">                 */</span></span><br><span class="line">                <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">clear</span><span class="params">()</span> &#123;</span><br><span class="line">                    AbstractMap.<span class="built_in">this</span>.clear();</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="comment">/**</span></span><br><span class="line"><span class="comment">                 * 判断迭代器是否包含元素v。</span></span><br><span class="line"><span class="comment">                 * 迭代器的contains()实现应当与AbstractMap.this.containsValue()一致</span></span><br><span class="line"><span class="comment">                 * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">                 */</span></span><br><span class="line">                <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">contains</span><span class="params">(Object v)</span> &#123;</span><br><span class="line">                    <span class="keyword">return</span> AbstractMap.<span class="built_in">this</span>.containsValue(v);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;;</span><br><span class="line">            <span class="comment">// 然后将一个实现的匿名类赋值给全局的values视图，第一次初始化视图</span></span><br><span class="line">            values = vals;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 直接返回vals</span></span><br><span class="line">        <span class="keyword">return</span> vals;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * entrySet继续抽象，交给子类去实现</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">abstract</span> Set&lt;Entry&lt;K,V&gt;&gt; <span class="title function_">entrySet</span><span class="params">()</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 比较与哈希操作</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 重写的equals()</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> o</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">equals</span><span class="params">(Object o)</span> &#123;</span><br><span class="line">        <span class="comment">// 先比较引用</span></span><br><span class="line">        <span class="keyword">if</span> (o == <span class="built_in">this</span>)</span><br><span class="line">            <span class="comment">// 若传进来的对象o就是当前this指向的对象，返回true</span></span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 判断是否属于Map的实现类</span></span><br><span class="line">        <span class="keyword">if</span> (!(o <span class="keyword">instanceof</span> Map))</span><br><span class="line">            <span class="comment">// 若不是Map的子类，说明肯定不是同类对象,直接返回false</span></span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        <span class="comment">// 强转为Map类型的对象</span></span><br><span class="line">        Map&lt;?,?&gt; m = (Map&lt;?,?&gt;) o;</span><br><span class="line">        <span class="comment">// 长度比较,若m的size和当前的size不一致,返回false</span></span><br><span class="line">        <span class="keyword">if</span> (m.size() != size())</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 获取entrySet集合的迭代器</span></span><br><span class="line">            Iterator&lt;Entry&lt;K,V&gt;&gt; i = entrySet().iterator();</span><br><span class="line">            <span class="comment">// 迭代遍历</span></span><br><span class="line">            <span class="keyword">while</span> (i.hasNext()) &#123;</span><br><span class="line">                <span class="comment">// 获取当前迭代的entry对象</span></span><br><span class="line">                Entry&lt;K,V&gt; e = i.next();</span><br><span class="line">                <span class="comment">// 获取key</span></span><br><span class="line">                <span class="type">K</span> <span class="variable">key</span> <span class="operator">=</span> e.getKey();</span><br><span class="line">                <span class="comment">// 获取value</span></span><br><span class="line">                <span class="type">V</span> <span class="variable">value</span> <span class="operator">=</span> e.getValue();</span><br><span class="line">                <span class="comment">// 判断value是否为null</span></span><br><span class="line">                <span class="keyword">if</span> (value == <span class="literal">null</span>) &#123;</span><br><span class="line">                    <span class="comment">// 若value为空,继续判断,根据当前的key去拿m映射中的value,判断m不存在该key或拿出来的不是null，则返回false</span></span><br><span class="line">                    <span class="keyword">if</span> (!(m.get(key)==<span class="literal">null</span> &amp;&amp; m.containsKey(key)))</span><br><span class="line">                        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="comment">// 若value非空,比对value和m取出来的value是否相同,不相同返回false</span></span><br><span class="line">                    <span class="keyword">if</span> (!value.equals(m.get(key)))</span><br><span class="line">                        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (ClassCastException unused) &#123;</span><br><span class="line">            <span class="comment">// 出现异常返回false</span></span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (NullPointerException unused) &#123;</span><br><span class="line">            <span class="comment">// 出现异常返回false</span></span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 其他情况返回true</span></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 返回当前map的hashCode</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">hashCode</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">// 定义变量h，存放当前对象的hashCode</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">h</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">        <span class="comment">// 获取entry集合的迭代器对象</span></span><br><span class="line">        Iterator&lt;Entry&lt;K,V&gt;&gt; i = entrySet().iterator();</span><br><span class="line">        <span class="comment">// 迭代遍历</span></span><br><span class="line">        <span class="keyword">while</span> (i.hasNext())</span><br><span class="line">            <span class="comment">// 将每个entry对象的hashCode累加到变量h</span></span><br><span class="line">            h += i.next().hashCode();</span><br><span class="line">        <span class="comment">// 返回最终的hashCode</span></span><br><span class="line">        <span class="keyword">return</span> h;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 重写的toString()</span></span><br><span class="line"><span class="comment">     * 思考,这个是不是多次一举:</span></span><br><span class="line"><span class="comment">     *  sb.append(value == this ? &quot;(this Map)&quot; : value);</span></span><br><span class="line"><span class="comment">     *  sb.append(key   == this ? &quot;(this Map)&quot; : key);</span></span><br><span class="line"><span class="comment">     *  答案:并不是多次一举, 请看下面代码:</span></span><br><span class="line"><span class="comment">     *  Map&lt;Object, Object&gt; map = new HashMap&lt;&gt;();</span></span><br><span class="line"><span class="comment">     *  map.put(&quot;k&quot;, &quot;v&quot;);</span></span><br><span class="line"><span class="comment">     *  map.put(map, map);</span></span><br><span class="line"><span class="comment">     *  如果不那样写，直接append(key)或append(value)，如果没有判断this的话，toString方法会一直执行，直到抛出StackOverflowError</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">// 获取entry集合的迭代器对象</span></span><br><span class="line">        Iterator&lt;Entry&lt;K,V&gt;&gt; i = entrySet().iterator();</span><br><span class="line">        <span class="comment">// 如果没有迭代元素, 直接返回“&#123;&#125;”字符</span></span><br><span class="line">        <span class="keyword">if</span> (! i.hasNext())</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;&#123;&#125;&quot;</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 创建一个StringBuilder字符串缓冲对象</span></span><br><span class="line">        <span class="type">StringBuilder</span> <span class="variable">sb</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringBuilder</span>();</span><br><span class="line">        <span class="comment">// 先添加一个前缀符号“&#123;”</span></span><br><span class="line">        sb.append(<span class="string">&#x27;&#123;&#x27;</span>);</span><br><span class="line">        <span class="comment">// 循环遍历, 死循环遍历法</span></span><br><span class="line">        <span class="keyword">for</span> (;;) &#123;</span><br><span class="line">            <span class="comment">// 获取entry对象</span></span><br><span class="line">            Entry&lt;K,V&gt; e = i.next();</span><br><span class="line">            <span class="comment">// 获取key</span></span><br><span class="line">            <span class="type">K</span> <span class="variable">key</span> <span class="operator">=</span> e.getKey();</span><br><span class="line">            <span class="comment">// 获取value</span></span><br><span class="line">            <span class="type">V</span> <span class="variable">value</span> <span class="operator">=</span> e.getValue();</span><br><span class="line">            <span class="comment">// 将key添加到字符串缓冲区中，思考: key   == this ? &quot;(this Map)&quot; : key)多次一举</span></span><br><span class="line">            sb.append(key   == <span class="built_in">this</span> ? <span class="string">&quot;(this Map)&quot;</span> : key);</span><br><span class="line">            <span class="comment">// 添加key和value的连接符“=”</span></span><br><span class="line">            sb.append(<span class="string">&#x27;=&#x27;</span>);</span><br><span class="line">            <span class="comment">// 将value添加到字符串缓冲区中，思考: value   == this ? &quot;(this Map)&quot; : value)多次一举</span></span><br><span class="line">            sb.append(value == <span class="built_in">this</span> ? <span class="string">&quot;(this Map)&quot;</span> : value);</span><br><span class="line">            <span class="comment">// 如果没有下一个元素，添加后缀&quot;&#125;&quot;,然后返回</span></span><br><span class="line">            <span class="keyword">if</span> (! i.hasNext())</span><br><span class="line">                <span class="keyword">return</span> sb.append(<span class="string">&#x27;&#125;&#x27;</span>).toString();</span><br><span class="line">            <span class="comment">// 连接符拼接</span></span><br><span class="line">            sb.append(<span class="string">&#x27;,&#x27;</span>).append(<span class="string">&#x27; &#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 浅拷贝,不拷贝keySet和values</span></span><br><span class="line"><span class="comment">     * 重写的clone()</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> CloneNotSupportedException</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">protected</span> Object <span class="title function_">clone</span><span class="params">()</span> <span class="keyword">throws</span> CloneNotSupportedException &#123;</span><br><span class="line">        <span class="comment">// 浅拷贝,Object.clone()</span></span><br><span class="line">        AbstractMap&lt;?,?&gt; result = (AbstractMap&lt;?,?&gt;)<span class="built_in">super</span>.clone();</span><br><span class="line">        <span class="comment">// 不拷贝keySet</span></span><br><span class="line">        result.keySet = <span class="literal">null</span>;</span><br><span class="line">        <span class="comment">// 不拷贝values</span></span><br><span class="line">        result.values = <span class="literal">null</span>;</span><br><span class="line">        <span class="comment">// 返回浅拷贝的map副本对象result</span></span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 静态的eq()比较方法,只比较两个对象的引用地址是否相同</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> o1</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> o2</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="type">boolean</span> <span class="title function_">eq</span><span class="params">(Object o1, Object o2)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> o1 == <span class="literal">null</span> ? o2 == <span class="literal">null</span> : o1.equals(o2);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     *  维护键和值的简单的Entry实现类。</span></span><br><span class="line"><span class="comment">     *  可以使用setValue方法来更改值。</span></span><br><span class="line"><span class="comment">     *  此类有助于构建自定义map实现的过程。</span></span><br><span class="line"><span class="comment">     *  例如，返回SimpleEntry实例的数组通过Map.entrySet().toArray()可能很方便。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> &lt;K&gt; Entry的key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> &lt;V&gt; Entry的value</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">SimpleEntry</span>&lt;K,V&gt;</span><br><span class="line">            <span class="keyword">implements</span> <span class="title class_">Entry</span>&lt;K,V&gt;, java.io.Serializable</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 序列化的UID</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> -<span class="number">8499721149061103585L</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 私有的key,并且定义为final不能修改</span></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> K key;</span><br><span class="line">        <span class="comment">// 私有的value</span></span><br><span class="line">        <span class="keyword">private</span> V value;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 键值构造器</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> value</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> <span class="title function_">SimpleEntry</span><span class="params">(K key, V value)</span> &#123;</span><br><span class="line">            <span class="built_in">this</span>.key   = key;</span><br><span class="line">            <span class="built_in">this</span>.value = value;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * Entry构造器</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> entry</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> <span class="title function_">SimpleEntry</span><span class="params">(Entry&lt;? extends K, ? extends V&gt; entry)</span> &#123;</span><br><span class="line">            <span class="built_in">this</span>.key   = entry.getKey();</span><br><span class="line">            <span class="built_in">this</span>.value = entry.getValue();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 获取key</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> K <span class="title function_">getKey</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> key;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 获取value</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> V <span class="title function_">getValue</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> value;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 重新设置value,并返回旧的值oldValue</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> value</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> V <span class="title function_">setValue</span><span class="params">(V value)</span> &#123;</span><br><span class="line">            <span class="type">V</span> <span class="variable">oldValue</span> <span class="operator">=</span> <span class="built_in">this</span>.value;</span><br><span class="line">            <span class="built_in">this</span>.value = value;</span><br><span class="line">            <span class="keyword">return</span> oldValue;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 重写的equals()</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> o</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">equals</span><span class="params">(Object o)</span> &#123;</span><br><span class="line">            <span class="comment">// 如果不是Map.Entry的子类实现,直接返回false</span></span><br><span class="line">            <span class="keyword">if</span> (!(o <span class="keyword">instanceof</span> Map.Entry))</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">            <span class="comment">// 强转为Map.Entry对象</span></span><br><span class="line">            Map.Entry&lt;?,?&gt; e = (Map.Entry&lt;?,?&gt;)o;</span><br><span class="line">            <span class="comment">// 对比key是否相同并value是否相同</span></span><br><span class="line">            <span class="keyword">return</span> eq(key, e.getKey()) &amp;&amp; eq(value, e.getValue());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 返回hashCode,取key和value的异或值</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">hashCode</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> (key   == <span class="literal">null</span> ? <span class="number">0</span> :   key.hashCode()) ^</span><br><span class="line">                    (value == <span class="literal">null</span> ? <span class="number">0</span> : value.hashCode());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 重写toString()</span></span><br><span class="line"><span class="comment">         * 用“=”连接符连接key和value</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> key + <span class="string">&quot;=&quot;</span> + value;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 实现不可修改的Entry类。</span></span><br><span class="line"><span class="comment">     * 该类不支持setValue操作。</span></span><br><span class="line"><span class="comment">     * 该类在返回键-值映射的线程安全快照的方法中可能很方便。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">SimpleImmutableEntry</span>&lt;K,V&gt;</span><br><span class="line">            <span class="keyword">implements</span> <span class="title class_">Entry</span>&lt;K,V&gt;, java.io.Serializable</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">// 序列化UID</span></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> <span class="number">7138329143949025153L</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 私有不可修改的key</span></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> K key;</span><br><span class="line">        <span class="comment">// 私有不可修改的value</span></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> V value;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 键值构造器</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> key</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> value</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> <span class="title function_">SimpleImmutableEntry</span><span class="params">(K key, V value)</span> &#123;</span><br><span class="line">            <span class="built_in">this</span>.key   = key;</span><br><span class="line">            <span class="built_in">this</span>.value = value;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * Entry构造器</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> entry the entry to copy</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> <span class="title function_">SimpleImmutableEntry</span><span class="params">(Entry&lt;? extends K, ? extends V&gt; entry)</span> &#123;</span><br><span class="line">            <span class="built_in">this</span>.key   = entry.getKey();</span><br><span class="line">            <span class="built_in">this</span>.value = entry.getValue();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 返回key</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> K <span class="title function_">getKey</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> key;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 返回value</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> V <span class="title function_">getValue</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> value;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 不支持setValue操作</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> value</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> V <span class="title function_">setValue</span><span class="params">(V value)</span> &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UnsupportedOperationException</span>();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> o</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">equals</span><span class="params">(Object o)</span> &#123;</span><br><span class="line">            <span class="comment">// 如果不是Map.Entry的子类实现,直接返回false</span></span><br><span class="line">            <span class="keyword">if</span> (!(o <span class="keyword">instanceof</span> Map.Entry))</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">            <span class="comment">// 强转为Map.Entry类型</span></span><br><span class="line">            Map.Entry&lt;?,?&gt; e = (Map.Entry&lt;?,?&gt;)o;</span><br><span class="line">            <span class="comment">// 对比key是否相同并value是否相同</span></span><br><span class="line">            <span class="keyword">return</span> eq(key, e.getKey()) &amp;&amp; eq(value, e.getValue());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 返回hashCode,取key和value的异或值</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">hashCode</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> (key   == <span class="literal">null</span> ? <span class="number">0</span> :   key.hashCode()) ^</span><br><span class="line">                    (value == <span class="literal">null</span> ? <span class="number">0</span> : value.hashCode());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 重写toString()</span></span><br><span class="line"><span class="comment">         * 用“=”连接符连接key和value</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> key + <span class="string">&quot;=&quot;</span> + value;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h1 id="2-HashMap源码分析"><a href="#2-HashMap源码分析" class="headerlink" title="2. HashMap源码分析"></a>2. HashMap源码分析</h1><h2 id="2-1-成员变量"><a href="#2-1-成员变量" class="headerlink" title="2.1 成员变量"></a>2.1 成员变量</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HashMap</span>&lt;K,V&gt; <span class="keyword">extends</span> <span class="title class_">AbstractMap</span>&lt;K,V&gt;</span><br><span class="line">        <span class="keyword">implements</span> <span class="title class_">Map</span>&lt;K,V&gt;, Cloneable, Serializable &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/** 序列化UID */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> <span class="number">362498820763181265L</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 默认位桶数组初始容量,必须是2的幂,这里默认是16</span></span><br><span class="line"><span class="comment">     * The default initial capacity - MUST be a power of two.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">DEFAULT_INITIAL_CAPACITY</span> <span class="operator">=</span> <span class="number">1</span> &lt;&lt; <span class="number">4</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 位桶数组大小的最大值。构造参数的大小必须是2的几次幂并且小于等于1&lt;&lt;30</span></span><br><span class="line"><span class="comment">     * The maximum capacity, used if a higher value is implicitly specified</span></span><br><span class="line"><span class="comment">     * by either of the constructors with arguments.</span></span><br><span class="line"><span class="comment">     * MUST be a power of two &lt;= 1&lt;&lt;30.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">MAXIMUM_CAPACITY</span> <span class="operator">=</span> <span class="number">1</span> &lt;&lt; <span class="number">30</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 默认负载因子是0.75，可以在构造参数里设置</span></span><br><span class="line"><span class="comment">     * The load factor used when none specified in constructor.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">float</span> <span class="variable">DEFAULT_LOAD_FACTOR</span> <span class="operator">=</span> <span class="number">0.75f</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 树化阈值</span></span><br><span class="line"><span class="comment">     * 一个桶中的bin的存储方式由链表转换为红黑树的阈值，当链表大小超过TREEIFY_THRESHOLD的时候转换为红黑树</span></span><br><span class="line"><span class="comment">     * The bin count threshold for using a tree rather than list for a</span></span><br><span class="line"><span class="comment">     * bin.  Bins are converted to trees when adding an element to a</span></span><br><span class="line"><span class="comment">     * bin with at least this many nodes. The value must be greater</span></span><br><span class="line"><span class="comment">     * than 2 and should be at least 8 to mesh with assumptions in</span></span><br><span class="line"><span class="comment">     * tree removal about conversion back to plain bins upon</span></span><br><span class="line"><span class="comment">     * shrinkage.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">TREEIFY_THRESHOLD</span> <span class="operator">=</span> <span class="number">8</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 树退化阈值</span></span><br><span class="line"><span class="comment">     * 红黑数转换为链表(收缩机制)，当执行resize操作(此时HashMap的数据存储位置会重新计算)时,桶中bin的数量少于6时，此时收</span></span><br><span class="line"><span class="comment">     * 缩为普通链表，提高查询效率</span></span><br><span class="line"><span class="comment">     * The bin count threshold for untreeifying a (split) bin during a</span></span><br><span class="line"><span class="comment">     * resize operation. Should be less than TREEIFY_THRESHOLD, and at</span></span><br><span class="line"><span class="comment">     * most 6 to mesh with shrinkage detection under removal.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">UNTREEIFY_THRESHOLD</span> <span class="operator">=</span> <span class="number">6</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 最小树形化容量阈值,即当哈希表中的容量 &gt; 该值时，才允许树形化链表(即将链表转换成红黑树),否则，若桶内元素太多时，则直接扩容，而不是树形化</span></span><br><span class="line"><span class="comment">     * 当桶中bin被树化时最小的hash表容量.(若没有达到这个阈值,即hash表容量小于MIN_TREEIFY_CAPACITY</span></span><br><span class="line"><span class="comment">     * 当桶中bin数量太多时会执行resize扩容操作).这个MIN_TREEIFY_CAPACITY的值至少TREEIFY_THRESHOLD</span></span><br><span class="line"><span class="comment">     * 的4倍。</span></span><br><span class="line"><span class="comment">     * The smallest table capacity for which bins may be treeified.</span></span><br><span class="line"><span class="comment">     * (Otherwise the table is resized if too many nodes in a bin.)</span></span><br><span class="line"><span class="comment">     * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts</span></span><br><span class="line"><span class="comment">     * between resizing and treeification thresholds.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">MIN_TREEIFY_CAPACITY</span> <span class="operator">=</span> <span class="number">64</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 位桶数组，即Hash表，其大小总是2的几次幂，JDK1.7类型是Entry&lt;K,V&gt;[],JDK8优化成Node&lt;K,V&gt;[]</span></span><br><span class="line"><span class="comment">     * The table, initialized on first use, and resized as</span></span><br><span class="line"><span class="comment">     * necessary. When allocated, length is always a power of two.</span></span><br><span class="line"><span class="comment">     * (We also tolerate length zero in some operations to allow</span></span><br><span class="line"><span class="comment">     * bootstrapping mechanics that are currently not needed.)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">transient</span> Node&lt;K,V&gt;[] table;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 缓存的entrySet，即键值对映射对象，这里使用了AbstractMap的keyset()和values()</span></span><br><span class="line"><span class="comment">     * Holds cached entrySet(). Note that AbstractMap fields are used</span></span><br><span class="line"><span class="comment">     * for keySet() and values().</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">transient</span> Set&lt;Map.Entry&lt;K,V&gt;&gt; entrySet;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 当前map中包含的key-value数，即map的大小</span></span><br><span class="line"><span class="comment">     * The number of key-value mappings contained in this map.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">transient</span> <span class="type">int</span> size;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * HashMap的修改次数，在迭代器初始化过程中会将这个值赋给迭代器的expectedModCount，</span></span><br><span class="line"><span class="comment">     * 比如迭代器迭代时候我们手动删除元素时，modCount会增加这个值。在迭代过程中，判断modCount和</span></span><br><span class="line"><span class="comment">     * expectedModCount是否相等，不相等则抛出ConcurrentModificationException异常，这就是所谓的</span></span><br><span class="line"><span class="comment">     * Fail-Fast机制。同样，ArrayList,LinkedList也有这个字段。</span></span><br><span class="line"><span class="comment">     * 具体详情请参照HashMap源码下的抽象迭代类HashIterator，</span></span><br><span class="line"><span class="comment">     * The number of times this HashMap has been structurally modified</span></span><br><span class="line"><span class="comment">     * Structural modifications are those that change the number of mappings in</span></span><br><span class="line"><span class="comment">     * the HashMap or otherwise modify its internal structure (e.g.,</span></span><br><span class="line"><span class="comment">     * rehash).  This field is used to make iterators on Collection-views of</span></span><br><span class="line"><span class="comment">     * the HashMap fail-fast.  (See ConcurrentModificationException).</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">transient</span> <span class="type">int</span> modCount;</span><br><span class="line"></span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 要根据threshold的阈值来判断map是否要扩容，即threshold = capacity * load factor，</span></span><br><span class="line"><span class="comment">     * 第一次扩容为16 * 0.75 = 12 ， 当map的位桶数组容量为12的时，此时需要继续扩容。</span></span><br><span class="line"><span class="comment">     * The next size value at which to resize (capacity * load factor).</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@serial</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="comment">// (The javadoc description is true upon serialization.</span></span><br><span class="line">    <span class="comment">// Additionally, if the table array has not been allocated, this</span></span><br><span class="line">    <span class="comment">// field holds the initial array capacity, or zero signifying</span></span><br><span class="line">    <span class="comment">// DEFAULT_INITIAL_CAPACITY.)</span></span><br><span class="line">    <span class="type">int</span> threshold;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * hash table的负载因子，默认负载因子是DEFAULT_LOAD_FACTOR，即0.75</span></span><br><span class="line"><span class="comment">     * The load factor for the hash table.</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@serial</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">final</span> <span class="type">float</span> loadFactor;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="2-2-构造器"><a href="#2-2-构造器" class="headerlink" title="2.2 构造器"></a>2.2 构造器</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 多参构造器:</span></span><br><span class="line"><span class="comment"> * 构造一个具有指定初始容量和负载因子的空HashMap。</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  initialCapacity the initial capacity 初始化容量</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  loadFactor      the load factor  负载因子</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IllegalArgumentException if the initial capacity is negative or the load factor is nonpositive</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">HashMap</span><span class="params">(<span class="type">int</span> initialCapacity, <span class="type">float</span> loadFactor)</span> &#123;</span><br><span class="line">    <span class="comment">// 若初始化容量小于0.则抛出IllegalArgumentException异常</span></span><br><span class="line">    <span class="keyword">if</span> (initialCapacity &lt; <span class="number">0</span>)</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">&quot;Illegal initial capacity: &quot;</span> +</span><br><span class="line">                initialCapacity);</span><br><span class="line">    <span class="comment">// 若初始化容量大于最大容量,则最大容量就是初始化容量</span></span><br><span class="line">    <span class="keyword">if</span> (initialCapacity &gt; MAXIMUM_CAPACITY)</span><br><span class="line">        initialCapacity = MAXIMUM_CAPACITY;</span><br><span class="line">    <span class="comment">// 若负载因子小于等于0,或是NaN(非数字)，则抛出IllegalArgumentException异常</span></span><br><span class="line">    <span class="keyword">if</span> (loadFactor &lt;= <span class="number">0</span> || Float.isNaN(loadFactor))</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">&quot;Illegal load factor: &quot;</span> +</span><br><span class="line">                loadFactor);</span><br><span class="line">    <span class="comment">// 赋值负载因子</span></span><br><span class="line">    <span class="built_in">this</span>.loadFactor = loadFactor;</span><br><span class="line">    <span class="comment">// 计算threshold,后续和负载因子判断是否扩容</span></span><br><span class="line">    <span class="built_in">this</span>.threshold = tableSizeFor(initialCapacity);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 单构造器</span></span><br><span class="line"><span class="comment"> * 构造一个空的HashMap，它具有指定的初始容量和默认的负载系数（0.75）</span></span><br><span class="line"><span class="comment"> * Constructs an empty &lt;tt&gt;HashMap&lt;/tt&gt; with the specified initial</span></span><br><span class="line"><span class="comment"> * capacity and the default load factor (0.75).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  initialCapacity the initial capacity.</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IllegalArgumentException if the initial capacity is negative.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">HashMap</span><span class="params">(<span class="type">int</span> initialCapacity)</span> &#123;</span><br><span class="line">    <span class="comment">// 调用另一个构造，只不过负载因子默认指定0.75</span></span><br><span class="line">    <span class="built_in">this</span>(initialCapacity, DEFAULT_LOAD_FACTOR);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 空参构造:</span></span><br><span class="line"><span class="comment"> * 构造一个空的HashMap，其默认初始容量*（16）和默认加载因子（0.75）</span></span><br><span class="line"><span class="comment"> * Constructs an empty &lt;tt&gt;HashMap&lt;/tt&gt; with the default initial capacity</span></span><br><span class="line"><span class="comment"> * (16) and the default load factor (0.75).</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">HashMap</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="built_in">this</span>.loadFactor = DEFAULT_LOAD_FACTOR; <span class="comment">// all other fields defaulted</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 单参构造:</span></span><br><span class="line"><span class="comment"> * 使用与指定的Map相同的映射构造一个新的HashMap。</span></span><br><span class="line"><span class="comment"> * 创建的HashMap具有默认的负载因子（0.75）和足以将映射保存在指定的Map中的初始容量。</span></span><br><span class="line"><span class="comment"> * 其实就是将其他Map接口的实现类转化为HashMap。</span></span><br><span class="line"><span class="comment"> * Constructs a new &lt;tt&gt;HashMap&lt;/tt&gt; with the same mappings as the</span></span><br><span class="line"><span class="comment"> * specified &lt;tt&gt;Map&lt;/tt&gt;.  The &lt;tt&gt;HashMap&lt;/tt&gt; is created with</span></span><br><span class="line"><span class="comment"> * default load factor (0.75) and an initial capacity sufficient to</span></span><br><span class="line"><span class="comment"> * hold the mappings in the specified &lt;tt&gt;Map&lt;/tt&gt;.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>   m the map whose mappings are to be placed in this map</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span>  NullPointerException if the specified map is null</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">HashMap</span><span class="params">(Map&lt;? extends K, ? extends V&gt; m)</span> &#123;</span><br><span class="line">    <span class="built_in">this</span>.loadFactor = DEFAULT_LOAD_FACTOR;</span><br><span class="line">    <span class="comment">// 将传入Map对象m的Entries映射放入HashMap中</span></span><br><span class="line">    putMapEntries(m, <span class="literal">false</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="2-3-红黑树实现"><a href="#2-3-红黑树实现" class="headerlink" title="2.3 红黑树实现"></a>2.3 红黑树实现</h2><h3 id="2-3-1-Node位桶节点"><a href="#2-3-1-Node位桶节点" class="headerlink" title="2.3.1 Node位桶节点"></a>2.3.1 Node位桶节点</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 基本的hash桶节点，即数组存放的元素类型，实现了Map.Entry&lt;K,V&gt;接口。</span></span><br><span class="line"><span class="comment"> * JDK1.7的结构是Map.Entry&lt;K, V&gt;的子类HashEntry&lt;K, V&gt;</span></span><br><span class="line"><span class="comment"> * Basic hash bin node, used for most entries.  (See below for</span></span><br><span class="line"><span class="comment"> * TreeNode subclass, and in LinkedHashMap for its Entry subclass.)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Node</span>&lt;K,V&gt; <span class="keyword">implements</span> <span class="title class_">Map</span>.Entry&lt;K,V&gt; &#123;</span><br><span class="line">    <span class="comment">// key的哈希值，用来定位数组索引位置</span></span><br><span class="line">    <span class="keyword">final</span> <span class="type">int</span> hash;</span><br><span class="line">    <span class="comment">// map的key，不可不变对象，一旦设置新Key，不可更改key的值，HashMap中可存null值</span></span><br><span class="line">    <span class="keyword">final</span> K key;</span><br><span class="line">    <span class="comment">// map的value，也可以存放null值。key相同则覆盖value,</span></span><br><span class="line">    V value;</span><br><span class="line">    <span class="comment">// 链表的下一个node</span></span><br><span class="line">    Node&lt;K,V&gt; next;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 构造函数</span></span><br><span class="line">    Node(<span class="type">int</span> hash, K key, V value, Node&lt;K,V&gt; next) &#123;</span><br><span class="line">        <span class="built_in">this</span>.hash = hash;</span><br><span class="line">        <span class="built_in">this</span>.key = key;</span><br><span class="line">        <span class="built_in">this</span>.value = value;</span><br><span class="line">        <span class="built_in">this</span>.next = next;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 获取key</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> K <span class="title function_">getKey</span><span class="params">()</span>        &#123; <span class="keyword">return</span> key; &#125;</span><br><span class="line">    <span class="comment">// 获取value</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> V <span class="title function_">getValue</span><span class="params">()</span>      &#123; <span class="keyword">return</span> value; &#125;</span><br><span class="line">    <span class="comment">// 重写toString</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> String <span class="title function_">toString</span><span class="params">()</span> &#123; <span class="keyword">return</span> key + <span class="string">&quot;=&quot;</span> + value; &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 重写hashCode，node的hashCode为key的hashCode与value的hashCode的异或结果</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="type">int</span> <span class="title function_">hashCode</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> Objects.hashCode(key) ^ Objects.hashCode(value);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 设置新的value，返回旧的value</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> V <span class="title function_">setValue</span><span class="params">(V newValue)</span> &#123;</span><br><span class="line">        <span class="type">V</span> <span class="variable">oldValue</span> <span class="operator">=</span> value;</span><br><span class="line">        value = newValue;</span><br><span class="line">        <span class="keyword">return</span> oldValue;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 一般重写了hashCode方法，equals也会重写。</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">final</span> <span class="type">boolean</span> <span class="title function_">equals</span><span class="params">(Object o)</span> &#123;</span><br><span class="line">        <span class="comment">// 引用都是一个，则判断是同一个对象，直接返回true</span></span><br><span class="line">        <span class="keyword">if</span> (o == <span class="built_in">this</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        <span class="comment">// 判断是否是Map.Entry同一类型，若类型不同，则返回false</span></span><br><span class="line">        <span class="keyword">if</span> (o <span class="keyword">instanceof</span> Map.Entry) &#123;</span><br><span class="line">            <span class="comment">// 若是 Map.Entry类型，进行向下转型。</span></span><br><span class="line">            Map.Entry&lt;?,?&gt; e = (Map.Entry&lt;?,?&gt;)o;</span><br><span class="line">            <span class="comment">// 如果两个对象的key和value同时都相等，则认为是相等，返回true</span></span><br><span class="line">            <span class="keyword">if</span> (Objects.equals(key, e.getKey()) &amp;&amp;</span><br><span class="line">                Objects.equals(value, e.getValue()))</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="2-3-2-TreeNode红黑树"><a href="#2-3-2-TreeNode红黑树" class="headerlink" title="2.3.2 TreeNode红黑树"></a>2.3.2 TreeNode红黑树</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 红黑树节点，继承LinkedHashMap.Entry&lt;K,V&gt;</span></span><br><span class="line"><span class="comment"> * Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn</span></span><br><span class="line"><span class="comment"> * extends Node) so can be used as extension of either regular or</span></span><br><span class="line"><span class="comment"> * linked node.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">TreeNode</span>&lt;K,V&gt; <span class="keyword">extends</span> <span class="title class_">LinkedHashMap</span>.Entry&lt;K,V&gt; &#123;</span><br><span class="line">    TreeNode&lt;K,V&gt; parent;  <span class="comment">// red-black tree links</span></span><br><span class="line">    TreeNode&lt;K,V&gt; left;</span><br><span class="line">    TreeNode&lt;K,V&gt; right;</span><br><span class="line">    TreeNode&lt;K,V&gt; prev;    <span class="comment">// needed to unlink next upon deletion</span></span><br><span class="line">    <span class="type">boolean</span> red;</span><br><span class="line">    TreeNode(<span class="type">int</span> hash, K key, V val, Node&lt;K,V&gt; next) &#123;</span><br><span class="line">        <span class="built_in">super</span>(hash, key, val, next);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns root of tree containing this node.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">final</span> TreeNode&lt;K,V&gt; <span class="title function_">root</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">for</span> (TreeNode&lt;K,V&gt; r = <span class="built_in">this</span>, p;;) &#123;</span><br><span class="line">            <span class="keyword">if</span> ((p = r.parent) == <span class="literal">null</span>)</span><br><span class="line">                <span class="keyword">return</span> r;</span><br><span class="line">            r = p;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * 把红黑树的根节点设为  其所在的数组槽 的第一个元素</span></span><br><span class="line"><span class="comment">   * 首先明确：TreeNode既是一个红黑树结构，也是一个双链表结构</span></span><br><span class="line"><span class="comment">   * 这个方法里做的事情，就是保证树的根节点一定也要成为链表的首节点</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">    <span class="keyword">static</span> &lt;K,V&gt; <span class="keyword">void</span> <span class="title function_">moveRootToFront</span><span class="params">(Node&lt;K,V&gt;[] tab, TreeNode&lt;K,V&gt; root)</span> &#123;</span><br><span class="line">        <span class="type">int</span> n;</span><br><span class="line">        <span class="keyword">if</span> (root != <span class="literal">null</span> &amp;&amp; tab != <span class="literal">null</span> &amp;&amp; (n = tab.length) &gt; <span class="number">0</span>) &#123; <span class="comment">// 根节点不为空 并且 HashMap的元素数组不为空</span></span><br><span class="line">            <span class="type">int</span> <span class="variable">index</span> <span class="operator">=</span> (n - <span class="number">1</span>) &amp; root.hash; <span class="comment">// 根据根节点的Hash值 和 HashMap的元素数组长度  取得根节点在数组中的位置</span></span><br><span class="line">            TreeNode&lt;K,V&gt; first = (TreeNode&lt;K,V&gt;)tab[index]; <span class="comment">// 首先取得该位置上的第一个节点对象</span></span><br><span class="line">            <span class="keyword">if</span> (root != first) &#123; <span class="comment">// 如果该节点对象 与 根节点对象 不同</span></span><br><span class="line">                Node&lt;K,V&gt; rn; <span class="comment">// 定义根节点的后一个节点</span></span><br><span class="line">                tab[index] = root; <span class="comment">// 把元素数组index位置的元素替换为根节点对象</span></span><br><span class="line">                TreeNode&lt;K,V&gt; rp = root.prev; <span class="comment">// 获取根节点对象的前一个节点</span></span><br><span class="line">                <span class="keyword">if</span> ((rn = root.next) != <span class="literal">null</span>) <span class="comment">// 如果后节点不为空 </span></span><br><span class="line">                    ((TreeNode&lt;K,V&gt;)rn).prev = rp; <span class="comment">// root后节点的前节点  指向到 root的前节点，相当于把root从链表中摘除</span></span><br><span class="line">                <span class="keyword">if</span> (rp != <span class="literal">null</span>) <span class="comment">// 如果root的前节点不为空</span></span><br><span class="line">                    rp.next = rn; <span class="comment">// root前节点的后节点 指向到 root的后节点</span></span><br><span class="line">                <span class="keyword">if</span> (first != <span class="literal">null</span>) <span class="comment">// 如果数组该位置上原来的元素不为空</span></span><br><span class="line">                    first.prev = root; <span class="comment">// 这个原有的元素的 前节点 指向到 root，相当于root目前位于链表首位</span></span><br><span class="line">                root.next = first; <span class="comment">// 原来的第一个节点现在作为root的下一个节点，变成了第二个节点</span></span><br><span class="line">                root.prev = <span class="literal">null</span>; <span class="comment">// 首节点没有前节点</span></span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">/*</span></span><br><span class="line"><span class="comment">         * 这一步是防御性的编程</span></span><br><span class="line"><span class="comment">         * 校验TreeNode对象是否满足红黑树和双链表的特性</span></span><br><span class="line"><span class="comment">         * 如果这个方法校验不通过：可能是因为用户编程失误，破坏了结构（例如：并发场景下）；也可能是TreeNode</span></span><br><span class="line"><span class="comment">         * 的实现有问题（这个是理论上的以防万一）；</span></span><br><span class="line"><span class="comment">         */</span> </span><br><span class="line">            <span class="keyword">assert</span> <span class="title function_">checkInvariants</span><span class="params">(root)</span>; </span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 参数为HashMap的元素数组</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">    <span class="keyword">final</span> <span class="keyword">void</span> <span class="title function_">treeify</span><span class="params">(Node&lt;K,V&gt;[] tab)</span> &#123;</span><br><span class="line">        <span class="comment">// 定义树的根节点</span></span><br><span class="line">        TreeNode&lt;K,V&gt; root = <span class="literal">null</span>; </span><br><span class="line">        <span class="comment">// 遍历链表，x指向当前节点、next指向下一个节点</span></span><br><span class="line">        <span class="keyword">for</span> (TreeNode&lt;K,V&gt; x = <span class="built_in">this</span>, next; x != <span class="literal">null</span>; x = next) &#123; </span><br><span class="line">            next = (TreeNode&lt;K,V&gt;)x.next; <span class="comment">// 下一个节点</span></span><br><span class="line">            x.left = x.right = <span class="literal">null</span>; <span class="comment">// 设置当前节点的左右节点为空</span></span><br><span class="line">            <span class="keyword">if</span> (root == <span class="literal">null</span>) &#123; <span class="comment">// 如果还没有根节点</span></span><br><span class="line">                x.parent = <span class="literal">null</span>; <span class="comment">// 当前节点的父节点设为空</span></span><br><span class="line">                x.red = <span class="literal">false</span>; <span class="comment">// 当前节点的红色属性设为false（把当前节点设为黑色）</span></span><br><span class="line">                root = x; <span class="comment">// 根节点指向到当前节点</span></span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span> &#123; <span class="comment">// 如果已经存在根节点了</span></span><br><span class="line">                <span class="type">K</span> <span class="variable">k</span> <span class="operator">=</span> x.key; <span class="comment">// 取得当前链表节点的key</span></span><br><span class="line">                <span class="type">int</span> <span class="variable">h</span> <span class="operator">=</span> x.hash; <span class="comment">// 取得当前链表节点的hash值</span></span><br><span class="line">                Class&lt;?&gt; kc = <span class="literal">null</span>; <span class="comment">// 定义key所属的Class</span></span><br><span class="line">                <span class="keyword">for</span> (TreeNode&lt;K,V&gt; p = root;;) &#123; <span class="comment">// 从根节点开始遍历，此遍历没有设置边界，只能从内部跳出</span></span><br><span class="line">                    <span class="comment">// GOTO1</span></span><br><span class="line">                    <span class="type">int</span> dir, ph; <span class="comment">// dir 标识方向（左右）、ph标识当前树节点的hash值</span></span><br><span class="line">                    <span class="type">K</span> <span class="variable">pk</span> <span class="operator">=</span> p.key; <span class="comment">// 当前树节点的key</span></span><br><span class="line">                    <span class="keyword">if</span> ((ph = p.hash) &gt; h) <span class="comment">// 如果当前树节点hash值 大于 当前链表节点的hash值</span></span><br><span class="line">                        dir = -<span class="number">1</span>; <span class="comment">// 标识当前链表节点会放到当前树节点的左侧</span></span><br><span class="line">                    <span class="keyword">else</span> <span class="keyword">if</span> (ph &lt; h)</span><br><span class="line">                        dir = <span class="number">1</span>; <span class="comment">// 右侧</span></span><br><span class="line"></span><br><span class="line">                    <span class="comment">/*</span></span><br><span class="line"><span class="comment">                 * 如果两个节点的key的hash值相等，那么还要通过其他方式再进行比较</span></span><br><span class="line"><span class="comment">                 * 如果当前链表节点的key实现了comparable接口，并且当前树节点和链表节点是相同Class的实</span></span><br><span class="line"><span class="comment">                 * 例，那么通过comparable的方式再比较两者。</span></span><br><span class="line"><span class="comment">                 * 如果还是相等，最后再通过tieBreakOrder比较一次</span></span><br><span class="line"><span class="comment">                 */</span></span><br><span class="line">                    <span class="keyword">else</span> <span class="keyword">if</span> ((kc == <span class="literal">null</span> &amp;&amp;</span><br><span class="line">                              (kc = comparableClassFor(k)) == <span class="literal">null</span>) ||</span><br><span class="line">                             (dir = compareComparables(kc, k, pk)) == <span class="number">0</span>)</span><br><span class="line">                        dir = tieBreakOrder(k, pk);</span><br><span class="line"></span><br><span class="line">                    TreeNode&lt;K,V&gt; xp = p; <span class="comment">// 保存当前树节点</span></span><br><span class="line"></span><br><span class="line">                    <span class="comment">/*</span></span><br><span class="line"><span class="comment">                 * 如果dir 小于等于0 ： 当前链表节点一定放置在当前树节点的左侧，但不一定是该树节点的左孩</span></span><br><span class="line"><span class="comment">                 * 子，也可能是左孩子的右孩子 或者 更深层次的节点。如果dir 大于0 ： 当前链表节点一定放置在</span></span><br><span class="line"><span class="comment">                 * 当前树节点的右侧，但不一定是该树节点的右孩子，也可能是右孩子的左孩子 或者 更深层次的节</span></span><br><span class="line"><span class="comment">                 * 点。</span></span><br><span class="line"><span class="comment">                 * </span></span><br><span class="line"><span class="comment">                 * 如果当前树节点不是叶子节点，那么最终会以当前树节点的左孩子或者右孩子为起始节点  再从</span></span><br><span class="line"><span class="comment">                 * GOTO1 处开始 重新寻找自己（当前链表节点）的位置。</span></span><br><span class="line"><span class="comment">                 * 如果当前树节点就是叶子节点，那么根据dir的值，就可以把当前链表节点挂载到当前树节点的左或</span></span><br><span class="line"><span class="comment">                 * 者右侧了。</span></span><br><span class="line"><span class="comment">                 * 挂载之后，还需要重新把树进行平衡。平衡之后，就可以针对下一个链表节点进行处理了。</span></span><br><span class="line"><span class="comment">                 */</span></span><br><span class="line">                    <span class="keyword">if</span> ((p = (dir &lt;= <span class="number">0</span>) ? p.left : p.right) == <span class="literal">null</span>) &#123;</span><br><span class="line">                        x.parent = xp; <span class="comment">// 当前链表节点 作为 当前树节点的子节点</span></span><br><span class="line">                        <span class="keyword">if</span> (dir &lt;= <span class="number">0</span>)</span><br><span class="line">                            xp.left = x; <span class="comment">// 作为左孩子</span></span><br><span class="line">                        <span class="keyword">else</span></span><br><span class="line">                            xp.right = x; <span class="comment">// 作为右孩子</span></span><br><span class="line">                        root = balanceInsertion(root, x); <span class="comment">// 重新平衡</span></span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 把所有的链表节点都遍历完之后，最终构造出来的树可能经历多个平衡操作，根节点目前到底是链表的哪一个节点是不确定的</span></span><br><span class="line">        <span class="comment">// 因为我们要基于树来做查找，所以就应该把 tab[N] 得到的对象一定根节点对象，而目前只是链表的第一个节点对象，所以要做相应的处理。</span></span><br><span class="line">        moveRootToFront(tab, root); </span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="2-4-重要方法"><a href="#2-4-重要方法" class="headerlink" title="2.4 重要方法"></a>2.4 重要方法</h2><h3 id="2-4-1-hash方法"><a href="#2-4-1-hash方法" class="headerlink" title="2.4.1 hash方法"></a>2.4.1 hash方法</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 计算key的hash值.</span></span><br><span class="line"><span class="comment"> * 采用key作为基数进行高位运算，减少hash碰撞。</span></span><br><span class="line"><span class="comment"> * 低16位与高16位做异或运算，是在speed、 utility、quality三个方面进行权衡。</span></span><br><span class="line"><span class="comment"> * key为null则hashCode为0;不为null则将key的hashCode赋值给h，最终的hashCode = h ^ (h &gt;&gt;&gt; 16);</span></span><br><span class="line"><span class="comment"> * 这里我们要讲讲数组索引的计算方式：(n- 1) &amp; hash,n表示table.length</span></span><br><span class="line"><span class="comment"> * 这里通过key.hashCode()计算出key的哈希值，然后将哈希值h右移16位，再与原来的h做异或^运算，这一步是高位运</span></span><br><span class="line"><span class="comment"> * 算。设想一下，如果没有高位运算，那么hash值将是一个int型的32位数。而从2的-31次幂到2的31次幂之间，有将近几</span></span><br><span class="line"><span class="comment"> * 十亿的空间，如果我们的HashMap的table有这么长，内存早就爆了。所以这个散列值不能直接用来最终的取模运算，而</span></span><br><span class="line"><span class="comment"> * 需要先加入高位运算，将高16位和低16位的信息&quot;融合&quot;到一起，也称为&quot;扰动函数&quot;。这样才能保证hash值所有位的数值</span></span><br><span class="line"><span class="comment"> * 特征都保存下来而没有遗漏，从而使映射结果尽可能的松散。最后，根据 n-1 做与操作的取模运算。这里也能看出为什么</span></span><br><span class="line"><span class="comment"> * HashMap要限制table的长度为2的n次幂，因为这样，n-1可以保证二进制展示形式是（以16为例）0000 0000 0000 </span></span><br><span class="line"><span class="comment"> * 0000 0000 0000 0000 1111。在做&quot;与&quot;操作时，就等同于截取hash二进制值得后四位数据作为下标。这里也可以看</span></span><br><span class="line"><span class="comment"> * 出&quot;扰动函数&quot;的重要性了，如果高位不参与运算，那么高16位的hash特征几乎永远得不到展现，发生hash碰撞的几率就</span></span><br><span class="line"><span class="comment"> * 会增大，从而影响性能。</span></span><br><span class="line"><span class="comment"> * Computes key.hashCode() and spreads (XORs) higher bits of hash</span></span><br><span class="line"><span class="comment"> * to lower.  Because the table uses power-of-two masking, sets of</span></span><br><span class="line"><span class="comment"> * hashes that vary only in bits above the current mask will</span></span><br><span class="line"><span class="comment"> * always collide. (Among known examples are sets of Float keys</span></span><br><span class="line"><span class="comment"> * holding consecutive whole numbers in small tables.)  So we</span></span><br><span class="line"><span class="comment"> * apply a transform that spreads the impact of higher bits</span></span><br><span class="line"><span class="comment"> * downward. There is a tradeoff between speed, utility, and</span></span><br><span class="line"><span class="comment"> * quality of bit-spreading. Because many common sets of hashes</span></span><br><span class="line"><span class="comment"> * are already reasonably distributed (so don&#x27;t benefit from</span></span><br><span class="line"><span class="comment"> * spreading), and because we use trees to handle large sets of</span></span><br><span class="line"><span class="comment"> * collisions in bins, we just XOR some shifted bits in the</span></span><br><span class="line"><span class="comment"> * cheapest possible way to reduce systematic lossage, as well as</span></span><br><span class="line"><span class="comment"> * to incorporate impact of the highest bits that would otherwise</span></span><br><span class="line"><span class="comment"> * never be used in index calculations because of table bounds.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="title function_">hash</span><span class="params">(Object key)</span> &#123;</span><br><span class="line">    <span class="comment">// 存储key的hashCode值</span></span><br><span class="line">    <span class="type">int</span> h;</span><br><span class="line">    <span class="comment">// 若key为null,则hash值为0。若不为null,先将h右移16位进行高位运算，然后将得到的结果与h再次进行异或运算返回</span></span><br><span class="line">    <span class="keyword">return</span> (key == <span class="literal">null</span>) ? <span class="number">0</span> : (h = key.hashCode()) ^ (h &gt;&gt;&gt; <span class="number">16</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="2-4-2-tableSizeFor方法"><a href="#2-4-2-tableSizeFor方法" class="headerlink" title="2.4.2 tableSizeFor方法"></a>2.4.2 tableSizeFor方法</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 对于给定的目标容量，返回两倍大小的幂。位运算快</span></span><br><span class="line"><span class="comment"> * 简单来说:cap=5返回8，cap=12返回16，离2的n次幂(2^n&gt;cap)最近的值</span></span><br><span class="line"><span class="comment"> * 返回大于输入参数且最近的2的整数次幂的数，例如输入14，则返回2的4次幂，即16。</span></span><br><span class="line"><span class="comment"> * 如果算出来的n大于等于最大的容量，则取最大的容量。</span></span><br><span class="line"><span class="comment"> * Returns a power of two size for the given target capacity.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="title function_">tableSizeFor</span><span class="params">(<span class="type">int</span> cap)</span> &#123;</span><br><span class="line">    <span class="type">int</span> <span class="variable">n</span> <span class="operator">=</span> cap - <span class="number">1</span>;</span><br><span class="line">    n |= n &gt;&gt;&gt; <span class="number">1</span>;</span><br><span class="line">    n |= n &gt;&gt;&gt; <span class="number">2</span>;</span><br><span class="line">    n |= n &gt;&gt;&gt; <span class="number">4</span>;</span><br><span class="line">    n |= n &gt;&gt;&gt; <span class="number">8</span>;</span><br><span class="line">    n |= n &gt;&gt;&gt; <span class="number">16</span>;</span><br><span class="line">    <span class="keyword">return</span> (n &lt; <span class="number">0</span>) ? <span class="number">1</span> : (n &gt;= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + <span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="2-4-3-size方法"><a href="#2-4-3-size方法" class="headerlink" title="2.4.3 size方法"></a>2.4.3 size方法</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 返回此map中的键值数</span></span><br><span class="line"><span class="comment"> * Returns the number of key-value mappings in this map.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the number of key-value mappings in this map</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">size</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> size;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="2-4-4-isEmpty方法"><a href="#2-4-4-isEmpty方法" class="headerlink" title="2.4.4 isEmpty方法"></a>2.4.4 isEmpty方法</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/** isEmpty方法</span></span><br><span class="line"><span class="comment"> * 若此map不包含键值映射关系，返回true</span></span><br><span class="line"><span class="comment"> * Returns &lt;tt&gt;true&lt;/tt&gt; if this map contains no key-value mappings.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &lt;tt&gt;true&lt;/tt&gt; if this map contains no key-value mappings</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isEmpty</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> size == <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="2-4-5-get方法"><a href="#2-4-5-get方法" class="headerlink" title="2.4.5 get方法"></a>2.4.5 get方法</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 我们实际用的get方法，底层调用的是getNode方法</span></span><br><span class="line"><span class="comment"> * 返回指定key映射的value;如果此映射不包含键的映射,则返回null.</span></span><br><span class="line"><span class="comment"> * Returns the value to which the specified key is mapped,</span></span><br><span class="line"><span class="comment"> * or &#123;<span class="doctag">@code</span> null&#125; if this map contains no mapping for the key.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;More formally, if this map contains a mapping from a key</span></span><br><span class="line"><span class="comment"> * &#123;<span class="doctag">@code</span> k&#125; to a value &#123;<span class="doctag">@code</span> v&#125; such that &#123;<span class="doctag">@code</span> (key==null ? k==null :</span></span><br><span class="line"><span class="comment"> * key.equals(k))&#125;, then this method returns &#123;<span class="doctag">@code</span> v&#125;; otherwise</span></span><br><span class="line"><span class="comment"> * it returns &#123;<span class="doctag">@code</span> null&#125;.  (There can be at most one such mapping.)</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;A return value of &#123;<span class="doctag">@code</span> null&#125; does not &lt;i&gt;necessarily&lt;/i&gt;</span></span><br><span class="line"><span class="comment"> * indicate that the map contains no mapping for the key; it&#x27;s also</span></span><br><span class="line"><span class="comment"> * possible that the map explicitly maps the key to &#123;<span class="doctag">@code</span> null&#125;.</span></span><br><span class="line"><span class="comment"> * The &#123;<span class="doctag">@link</span> #containsKey containsKey&#125; operation may be used to</span></span><br><span class="line"><span class="comment"> * distinguish these two cases.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@see</span> #put(Object, Object)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> V <span class="title function_">get</span><span class="params">(Object key)</span> &#123;</span><br><span class="line">    <span class="comment">// 定义一个Node节点，用于存放查找结果</span></span><br><span class="line">    Node&lt;K,V&gt; e;</span><br><span class="line">    <span class="comment">// 执行查找操作，将查找后的节点并返回</span></span><br><span class="line">    <span class="comment">// 根据key及其hash值查询node节点，如果存在，则返回该节点的value值；如果不存在，则返回null。</span></span><br><span class="line">    <span class="keyword">return</span> (e = getNode(hash(key), key)) == <span class="literal">null</span> ? <span class="literal">null</span> : e.value;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 实现Map.get相关的方法</span></span><br><span class="line"><span class="comment"> * Implements Map.get and related methods.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> hash hash for key</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> key the key</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the node, or null if none 。</span></span><br><span class="line"><span class="comment"> * 如果找到node返回node，没有找到node则返回null</span></span><br><span class="line"><span class="comment"> * 根据key搜索节点的方法。记住判断key相等的条件：hash值相同 并且 符合equals方法。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">final</span> Node&lt;K,V&gt; <span class="title function_">getNode</span><span class="params">(<span class="type">int</span> hash, Object key)</span> &#123;</span><br><span class="line">    <span class="comment">// 定义变量tab是将要遍历查找的Node数组引用，first和e表示tab上的找到的Node节点，n为tab的长度，k为Key</span></span><br><span class="line">    Node&lt;K,V&gt;[] tab; Node&lt;K,V&gt; first, e; <span class="type">int</span> n; K k;</span><br><span class="line">    <span class="comment">// 根据输入的hash值，可以直接计算出对应的下标(n - 1) &amp; hash，缩小查询范围，如果存在结果，则必定在table的这个位置上。</span></span><br><span class="line">    <span class="keyword">if</span> ((tab = table) != <span class="literal">null</span> &amp;&amp; (n = tab.length) &gt; <span class="number">0</span> &amp;&amp;</span><br><span class="line">        (first = tab[(n - <span class="number">1</span>) &amp; hash]) != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (first.hash == hash &amp;&amp; <span class="comment">// always check first node</span></span><br><span class="line">            ((k = first.key) == key || (key != <span class="literal">null</span> &amp;&amp; key.equals(k))))</span><br><span class="line">            <span class="comment">// 判断第一个存在的节点的key是否和查询的key相等。如果相等，直接返回该节点。</span></span><br><span class="line">            <span class="keyword">return</span> first;</span><br><span class="line">        <span class="comment">// 如果第一个不匹配，则判断它的下一个是红黑树还是链表。遍历该链表/红黑树直到next为null。</span></span><br><span class="line">        <span class="keyword">if</span> ((e = first.next) != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 红黑树就按照树的查找方式返回值。</span></span><br><span class="line">            <span class="keyword">if</span> (first <span class="keyword">instanceof</span> TreeNode)</span><br><span class="line">                <span class="comment">// 当这个table节点上存储的是红黑树结构时，在根节点first上调用getTreeNode方法，在内部遍历红黑树节点，查看是否有匹配的TreeNode。</span></span><br><span class="line">                <span class="keyword">return</span> ((TreeNode&lt;K,V&gt;)first).getTreeNode(hash, key);</span><br><span class="line">            <span class="comment">// 链表的方式遍历匹配返回值。  </span></span><br><span class="line">            <span class="keyword">do</span> &#123;</span><br><span class="line">                <span class="comment">// 当这个table节点上存储的是链表结构时，若两者hash相同且key是否完全相同则直接返回。</span></span><br><span class="line">                <span class="keyword">if</span> (e.hash == hash &amp;&amp;</span><br><span class="line">                    ((k = e.key) == key || (key != <span class="literal">null</span> &amp;&amp; key.equals(k))))</span><br><span class="line">                    <span class="keyword">return</span> e;</span><br><span class="line">                <span class="comment">// 如果key不同，一直遍历下去直到链表尽头，直到e.next == null才终止循环。</span></span><br><span class="line">            &#125; <span class="keyword">while</span> ((e = e.next) != <span class="literal">null</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 没有找到则返回null。</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="2-4-6-put方法"><a href="#2-4-6-put方法" class="headerlink" title="2.4.6 put方法"></a>2.4.6 put方法</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 将K-V添加到map中，如果存在K,覆盖V.</span></span><br><span class="line"><span class="comment"> * 实际调用的是putVal方法.</span></span><br><span class="line"><span class="comment"> * Associates the specified value with the specified key in this map.</span></span><br><span class="line"><span class="comment"> * If the map previously contained a mapping for the key, the old</span></span><br><span class="line"><span class="comment"> * value is replaced.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> key key with which the specified value is to be associated</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> value value to be associated with the specified key</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the previous value associated with &lt;tt&gt;key&lt;/tt&gt;, or</span></span><br><span class="line"><span class="comment"> *         &lt;tt&gt;null&lt;/tt&gt; if there was no mapping for &lt;tt&gt;key&lt;/tt&gt;.</span></span><br><span class="line"><span class="comment"> *         (A &lt;tt&gt;null&lt;/tt&gt; return can also indicate that the map</span></span><br><span class="line"><span class="comment"> *         previously associated &lt;tt&gt;null&lt;/tt&gt; with &lt;tt&gt;key&lt;/tt&gt;.)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> V <span class="title function_">put</span><span class="params">(K key, V value)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> putVal(hash(key), key, value, <span class="literal">false</span>, <span class="literal">true</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 实现Map.get相关的方法.</span></span><br><span class="line"><span class="comment"> * Implements Map.put and related methods.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> hash hash for key</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> key the key</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> value the value to put</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> onlyIfAbsent if true, don&#x27;t change existing value</span></span><br><span class="line"><span class="comment"> * (onlyIfAbsent为true时，如果key存在，就不会进行put操作，原有的对应的value不会被覆盖)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> evict if false, the table is in creation mode.</span></span><br><span class="line"><span class="comment"> * (evict参数用于LinkedHashMap中的尾部操作，这里没有实际意义。)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> previous value, or null if none</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">final</span> V <span class="title function_">putVal</span><span class="params">(<span class="type">int</span> hash, K key, V value, <span class="type">boolean</span> onlyIfAbsent,</span></span><br><span class="line"><span class="params">               <span class="type">boolean</span> evict)</span> &#123;</span><br><span class="line">    <span class="comment">// 定义变量tab是将要操作的Node数组引用，p表示tab上的某Node节点，n为tab的长度，i为tab的下标。</span></span><br><span class="line">    Node&lt;K,V&gt;[] tab; Node&lt;K,V&gt; p; <span class="type">int</span> n, i;</span><br><span class="line">    <span class="comment">// 判断当table为null或者tab的长度为0时，即table尚未初始化，此时通过resize()方法得到初始化的table。</span></span><br><span class="line">    <span class="keyword">if</span> ((tab = table) == <span class="literal">null</span> || (n = tab.length) == <span class="number">0</span>)</span><br><span class="line">        <span class="comment">// 这种情况是可能发生的，HashMap的table字段注释中提到：The table, initialized on first use,     and resized as necessary。</span></span><br><span class="line">        n = (tab = resize()).length;</span><br><span class="line">    <span class="comment">// 此处通过(n - 1)&amp; hash计算出的值作为tab的下标i，并另p表示tab[i]，也就是该链表第一个节点的位置。并判断p是否为null。</span></span><br><span class="line">    <span class="keyword">if</span> ((p = tab[i = (n - <span class="number">1</span>) &amp; hash]) == <span class="literal">null</span>)</span><br><span class="line">        <span class="comment">// 当p为null时，表明tab[i]上没有任何元素，即不存在Hash冲突，那么接下来就new第一个Node节点，调用newNode方法返回新节点赋值给tab[i]。这里值得注意的是i = (n - 1) &amp; hash相当于对hash对n的取模</span></span><br><span class="line">        tab[i] = newNode(hash, key, value, <span class="literal">null</span>);</span><br><span class="line">    <span class="comment">// 下面进入p不为null的情况，有三种情况：p为链表节点；p为红黑树节点；p是链表节点但长度为临界长度TREEIFY_THRESHOLD，再插入任何元素就要变成红黑树了。</span></span><br><span class="line">    <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">// 定义e引用,表示即将插入的Node节点，并且下文可以看出 k = p.key。</span></span><br><span class="line">        Node&lt;K,V&gt; e; K k;</span><br><span class="line">        <span class="keyword">if</span> (p.hash == hash &amp;&amp;</span><br><span class="line">            <span class="comment">// HashMap中判断key相同的条件是key的hash相同（Hash是否冲突），并且符合equals方法。这里判断了p.key是否和插入的key相等，如果相等，则将p的引用赋给e。e会在最后统一进行赋值及返回。</span></span><br><span class="line">            ((k = p.key) == key || (key != <span class="literal">null</span> &amp;&amp; key.equals(k))))</span><br><span class="line">            <span class="comment">// 这一步的判断其实是属于一种特殊情况，上述三个条件都满足，即两者hash值相同且key完全相同，于是插入操作就不需要了，只要把原来的value覆盖就可以了。e会在最后统一进行赋值及返回，这里先不进行覆盖操作。</span></span><br><span class="line">            e = p;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> (p <span class="keyword">instanceof</span> TreeNode)</span><br><span class="line">            <span class="comment">// 现在开始了第一种情况，当前桶p是红黑树节点，那么肯定插入后仍然是红黑树节点，就要按照红黑树的方式写入数据。所以我们直接强制转型p后调用TreeNode.putTreeVal方法，返回的引用赋给e。</span></span><br><span class="line">            <span class="comment">// 你可能好奇，这里怎么不遍历tree看看有没有key相同的节点呢？其实，putTreeVal内部进行了遍历，存在相同hash时返回被覆盖的TreeNode，否则返回null。</span></span><br><span class="line">            e = ((TreeNode&lt;K,V&gt;)p).putTreeVal(<span class="built_in">this</span>, tab, hash, key, value);</span><br><span class="line">        <span class="comment">// 接下里就是p为链表节点的情形，也就是上述说的另外两类情况：插入后还是链表/插入后转红黑树。另外，上行转型代码也说明了TreeNode是Node的一个子类。</span></span><br><span class="line">        <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// 我们需要一个计数器来计算当前链表的元素个数，并遍历链表，binCount就是这个计数器。</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">binCount</span> <span class="operator">=</span> <span class="number">0</span>; ; ++binCount) &#123;</span><br><span class="line">                <span class="comment">// 遍历过程中当发现p.next为null时，说明链表到头了，就需要将当前的key、value封装成一个新节点,将新的链表节点直接在p的后面插入即可，即把新节点的引用赋给p.next，插入操作就完成了。注意此时e赋给p。</span></span><br><span class="line">                <span class="keyword">if</span> ((e = p.next) == <span class="literal">null</span>) &#123;</span><br><span class="line">                    <span class="comment">// 最后一个参数为新节点的next，这里传入null，保证了新节点继续为该链表的末端。</span></span><br><span class="line">                    p.next = newNode(hash, key, value, <span class="literal">null</span>);</span><br><span class="line">                    <span class="comment">// 插入成功后，要判断是否需要转换为红黑树，因为插入后链表长度加1，而binCount并不包含新节点，所以判断时要将临界阈值减1。binCount大于等于7（其实实际上链表此时的大小为8）时转换为红黑树进行处理</span></span><br><span class="line">                    <span class="keyword">if</span> (binCount &gt;= TREEIFY_THRESHOLD - <span class="number">1</span>) <span class="comment">// -1 for 1st</span></span><br><span class="line">                        <span class="comment">// 当满足上述转换条件时，调用treeifyBin方法，将该链表转换为红黑树。</span></span><br><span class="line">                        treeifyBin(tab, hash);</span><br><span class="line">                    <span class="comment">// 当然如果不满足转换条件，那么插入数据后结构也无需变动，所有插入操作也到此结束了，break退出即可。</span></span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// 在遍历链表的过程中，有可能遍历到与插入的key相同的节点，此时只要将这个节点引用赋值给e，最后通过e去把新的value覆盖掉就可以了。</span></span><br><span class="line">                <span class="keyword">if</span> (e.hash == hash &amp;&amp;</span><br><span class="line">                    ((k = e.key) == key || (key != <span class="literal">null</span> &amp;&amp; key.equals(k))))</span><br><span class="line">                    <span class="comment">// 找到了相同key的节点，那么插入操作也不需要了，直接break退出循环进行最后的value覆盖操作。</span></span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="comment">// e是当前遍历的节点p的下一个节点，p = e 就是依次遍历链表的核心语句。每次循环时p都是下一个node节点。</span></span><br><span class="line">                p = e;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 下面JDK注释已经很清晰了，针对已经存在key的情况做处理。即我们对e进行处理。</span></span><br><span class="line">        <span class="keyword">if</span> (e != <span class="literal">null</span>) &#123; <span class="comment">// existing mapping for key</span></span><br><span class="line">            <span class="comment">//定义oldValue，即原存在的节点e的value值。 </span></span><br><span class="line">            <span class="type">V</span> <span class="variable">oldValue</span> <span class="operator">=</span> e.value;</span><br><span class="line">            <span class="comment">// 方法注释提到，onlyIfAbsent为true时，若存在key相同时不做覆盖处理，这里作为判断条件，可以看出当onlyIfAbsent为默认值false或者oldValue为null时，进行覆盖操作。</span></span><br><span class="line">            <span class="keyword">if</span> (!onlyIfAbsent || oldValue == <span class="literal">null</span>)</span><br><span class="line">                <span class="comment">// 覆盖操作，将原节点e上的value设置为插入的新value。</span></span><br><span class="line">                e.value = value;</span><br><span class="line">            <span class="comment">// 这个函数在hashmap中没有任何操作，是个空函数，它存在主要是为了linkedHashMap的一些后续处理工作。</span></span><br><span class="line">            afterNodeAccess(e);</span><br><span class="line">            <span class="comment">// 返回的是被覆盖的oldValue。我们在使用put方法时很少用他的返回值，甚至忘了它的存在，这里我们知道，他返回的是被覆盖的oldValue。</span></span><br><span class="line">            <span class="keyword">return</span> oldValue;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 收尾工作，值得一提的是，对key相同而覆盖oldValue的情况，在前面已经return，不会执行这里，所以那一类情况不算数据结构变化，并不改变modCount值。如果走到这里，说明已经新增一个Key-Value的Node节点，modCount要自增</span></span><br><span class="line">    ++modCount;</span><br><span class="line">    <span class="comment">// 同理，覆盖oldValue时显然没有新元素添加，除此之外都新增了一个元素，这里++size并与threshold判断是否达到了扩容标准。</span></span><br><span class="line">    <span class="keyword">if</span> (++size &gt; threshold)</span><br><span class="line">        <span class="comment">// 当HashMap中存在的node节点大于threshold时，hashmap进行扩容。</span></span><br><span class="line">        resize();</span><br><span class="line">    <span class="comment">// 这里与前面的afterNodeAccess同理，是用于linkedHashMap的尾部操作，HashMap中并无实际意义。</span></span><br><span class="line">    afterNodeInsertion(evict);</span><br><span class="line">    <span class="comment">// 最终，对于真正进行插入元素(不是覆盖的操作)的情况，put函数一律返回null。</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="2-4-7-resize方法"><a href="#2-4-7-resize方法" class="headerlink" title="2.4.7 resize方法"></a>2.4.7 resize方法</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * map扩容机制</span></span><br><span class="line"><span class="comment"> * Initializes or doubles table size.  If null, allocates in</span></span><br><span class="line"><span class="comment"> * accord with initial capacity target held in field threshold.</span></span><br><span class="line"><span class="comment"> * Otherwise, because we are using power-of-two expansion, the</span></span><br><span class="line"><span class="comment"> * elements from each bin must either stay at same index, or move</span></span><br><span class="line"><span class="comment"> * with a power of two offset in the new table.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the table</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">final</span> Node&lt;K,V&gt;[] resize() &#123;</span><br><span class="line">    <span class="comment">// 当前所有元素所在的数组，称为老的元素数组</span></span><br><span class="line">    Node&lt;K,V&gt;[] oldTab = table;</span><br><span class="line">    <span class="comment">// 老的元素数组长度</span></span><br><span class="line">    <span class="type">int</span> <span class="variable">oldCap</span> <span class="operator">=</span> (oldTab == <span class="literal">null</span>) ? <span class="number">0</span> : oldTab.length;</span><br><span class="line">    <span class="comment">// 老的扩容阀值设置</span></span><br><span class="line">    <span class="type">int</span> <span class="variable">oldThr</span> <span class="operator">=</span> threshold;</span><br><span class="line">    <span class="comment">// 新数组的容量，新数组的扩容阀值都初始化为0</span></span><br><span class="line">    <span class="type">int</span> newCap, newThr = <span class="number">0</span>;</span><br><span class="line">    <span class="comment">// 如果老数组长度大于0，说明已经存在元素</span></span><br><span class="line">    <span class="keyword">if</span> (oldCap &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="comment">// 超过最大值就不再扩充了，即2的30次方时，就只好随你碰撞去吧</span></span><br><span class="line">        <span class="keyword">if</span> (oldCap &gt;= MAXIMUM_CAPACITY) &#123;</span><br><span class="line">            <span class="comment">// 扩容阀值设置为int最大值（2的31次方 -1 ），因为oldCap再乘2就溢出了。</span></span><br><span class="line">            threshold = Integer.MAX_VALUE;</span><br><span class="line">            <span class="comment">// 超过了最大的容量，不能扩容，直接返回老的元素数组</span></span><br><span class="line">            <span class="keyword">return</span> oldTab;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">/* 没超过最大值，就扩充为原来的2倍</span></span><br><span class="line"><span class="comment">         * 如果数组元素个数在正常范围内，那么新的数组容量为老的数组容量的2倍（左移1位相当于乘以2）</span></span><br><span class="line"><span class="comment">         * 如果扩容之后的新容量小于最大容量并且老的数组容量大于等于默认初始化容量（16），那么新数组的扩</span></span><br><span class="line"><span class="comment">         * 容阀值设置为老阀值的2倍。（老的数组容量大于16意味着：要么构造函数指定了一个大于16的初始化容量值，</span></span><br><span class="line"><span class="comment">         * 要么已经经历过了至少一次扩容）</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> ((newCap = oldCap &lt;&lt; <span class="number">1</span>) &lt; MAXIMUM_CAPACITY &amp;&amp;</span><br><span class="line">                 oldCap &gt;= DEFAULT_INITIAL_CAPACITY)</span><br><span class="line">            newThr = oldThr &lt;&lt; <span class="number">1</span>; <span class="comment">// double threshold</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 运行到这个else if,说明老数组没有任何元素</span></span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (oldThr &gt; <span class="number">0</span>) <span class="comment">// initial capacity was placed in threshold</span></span><br><span class="line">        <span class="comment">// 如果老数组的扩容阀值大于0，那么设置新数组的容量为该阀值,这一步也就意味着构造该map的时候，指定了初始化容量</span></span><br><span class="line">        newCap = oldThr;</span><br><span class="line">    <span class="keyword">else</span> &#123;               <span class="comment">// zero initial threshold signifies using defaults</span></span><br><span class="line">        <span class="comment">// 能运行到这里的话，说明是调用无参构造函数创建的该map，并且第一次添加元素</span></span><br><span class="line">        <span class="comment">// 设置新数组容量为16</span></span><br><span class="line">        newCap = DEFAULT_INITIAL_CAPACITY;</span><br><span class="line">        <span class="comment">// 设置新数组扩容阀值为 16 * 0.75 = 12。0.75为负载因子(当元素个数达到容量了4分之3，那么扩容)</span></span><br><span class="line">        newThr = (<span class="type">int</span>)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 如果扩容阀值为0</span></span><br><span class="line">    <span class="keyword">if</span> (newThr == <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="comment">// 计算新的resize上限</span></span><br><span class="line">        <span class="type">float</span> <span class="variable">ft</span> <span class="operator">=</span> (<span class="type">float</span>)newCap * loadFactor;</span><br><span class="line">        <span class="comment">// 计算扩容阀值</span></span><br><span class="line">        newThr = (newCap &lt; MAXIMUM_CAPACITY &amp;&amp; ft &lt; (<span class="type">float</span>)MAXIMUM_CAPACITY ?</span><br><span class="line">                  (<span class="type">int</span>)ft : Integer.MAX_VALUE);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 设置新数组的扩容阀值</span></span><br><span class="line">    threshold = newThr;</span><br><span class="line">    <span class="meta">@SuppressWarnings(&#123;&quot;rawtypes&quot;,&quot;unchecked&quot;&#125;)</span></span><br><span class="line">    <span class="comment">// 创建新的数组（对于第一次添加元素，那么这个数组就是第一个数组；对于存在oldTab的时候，那么这个数组就是要需要扩容到的新数组）</span></span><br><span class="line">    Node&lt;K,V&gt;[] newTab = (Node&lt;K,V&gt;[])<span class="keyword">new</span> <span class="title class_">Node</span>[newCap];</span><br><span class="line">    <span class="comment">// 将该map的table属性指向到该新数组newTab</span></span><br><span class="line">    table = newTab;</span><br><span class="line">    <span class="comment">// 如果老数组不为空，说明是扩容操作，那么涉及到元素的转移操作</span></span><br><span class="line">    <span class="keyword">if</span> (oldTab != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="comment">// 遍历老数组把每个bucket都移动到新的buckets中</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">j</span> <span class="operator">=</span> <span class="number">0</span>; j &lt; oldCap; ++j) &#123;</span><br><span class="line">            <span class="comment">// 数组中的某个元素</span></span><br><span class="line">            Node&lt;K,V&gt; e;</span><br><span class="line">            <span class="comment">// 如果当前位置元素不为空，那么需要转移该元素到新数组</span></span><br><span class="line">            <span class="keyword">if</span> ((e = oldTab[j]) != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="comment">// 释放掉老数组对于要转移走的元素的引用（主要为了使得数组可被回收）</span></span><br><span class="line">                oldTab[j] = <span class="literal">null</span>;</span><br><span class="line">                <span class="comment">// 如果元素没有有下一个节点，说明该元素不存在hash冲突</span></span><br><span class="line">                <span class="keyword">if</span> (e.next == <span class="literal">null</span>)</span><br><span class="line">                    <span class="comment">// 把元素存储到新的数组中，存储到数组的哪个位置需要根据hash值和数组长度来进行取模</span></span><br><span class="line">                    <span class="comment">// 【hash值  %   数组长度】 = 【  hash值   &amp; （数组长度-1）】</span></span><br><span class="line">                    <span class="comment">//  这种与运算求模的方式要求  数组长度必须是2的N次方，但是可以通过构造函数随意指定初始化容量呀，如果指定了17,15这种，岂不是出问题了就？没关系，最终会通过tableSizeFor方法将用户指定的转化为大于其并且最相近的2的N次方。 15 -&gt; 16、17-&gt; 32</span></span><br><span class="line">                    newTab[e.hash &amp; (newCap - <span class="number">1</span>)] = e;</span><br><span class="line">                <span class="comment">/*</span></span><br><span class="line"><span class="comment">                 * 如果该元素有下一个节点，那么说明该位置上存在一个链表了（hash相同的多个元素以链表的方式存</span></span><br><span class="line"><span class="comment">                 * 储到了老数组的这个位置上了）。例如：数组长度为16，那么hash值为1（1%16=1）的和hash值为</span></span><br><span class="line"><span class="comment">                 * 17（17%16=1）的两个元素都是会存储在数组的第2个位置上（对应数组下标为1），当数组扩容为</span></span><br><span class="line"><span class="comment">                 * 32（1%32=1）时，hash值为1的还应该存储在新数组的第二个位置上，但是hash值为17(17%32=1</span></span><br><span class="line"><span class="comment">                 * 7)的就应该存储在新数组的第18个位置上了。所以，数组扩容后，所有元素都需要重新计算在新数组</span></span><br><span class="line"><span class="comment">                 * 中的位置。</span></span><br><span class="line"><span class="comment">                 */</span></span><br><span class="line">                <span class="keyword">else</span> <span class="keyword">if</span> (e <span class="keyword">instanceof</span> TreeNode)</span><br><span class="line">                    <span class="comment">// 如果该节点为TreeNode类型</span></span><br><span class="line">                    ((TreeNode&lt;K,V&gt;)e).split(<span class="built_in">this</span>, newTab, j, oldCap);</span><br><span class="line">                <span class="keyword">else</span> &#123; <span class="comment">// preserve order</span></span><br><span class="line">                    <span class="comment">// 链表优化重hash的代码块</span></span><br><span class="line">                    <span class="comment">// 按命名来翻译的话，应该叫低位首尾节点</span></span><br><span class="line">                    Node&lt;K,V&gt; loHead = <span class="literal">null</span>, loTail = <span class="literal">null</span>; </span><br><span class="line">                    <span class="comment">// 按命名来翻译的话，应该叫高位首尾节点</span></span><br><span class="line">                    Node&lt;K,V&gt; hiHead = <span class="literal">null</span>, hiTail = <span class="literal">null</span>;</span><br><span class="line">                    <span class="comment">// 以上的低位指的是新数组的 0  到 oldCap-1 、高位指定的是oldCap 到 newCap - 1</span></span><br><span class="line">                    Node&lt;K,V&gt; next;</span><br><span class="line">                    <span class="comment">// 遍历链表</span></span><br><span class="line">                    <span class="keyword">do</span> &#123;</span><br><span class="line">                        <span class="comment">// next表示下一个node节点</span></span><br><span class="line">                        next = e.next;</span><br><span class="line">                        <span class="comment">// 原索引</span></span><br><span class="line">                        <span class="comment">// 这一步判断好狠，拿元素的hash值和老数组的长度做与运算</span></span><br><span class="line">                        <span class="comment">// 数组的长度一定是2的N次方(例如16)，如果hash值和该长度做与运算，结果为0，就说明该hash值和数组长度取模后的值一定小于数组长度（例如mod值为1）。</span></span><br><span class="line">                        <span class="comment">// 那么该hash值再和新数组的长度取摸的话mod值也不会放生变化，所以该元素的在新数组的位置和在老数组的位置是相同的，所以该元素可以放置在低位链表中。</span></span><br><span class="line">                        <span class="keyword">if</span> ((e.hash &amp; oldCap) == <span class="number">0</span>) &#123;</span><br><span class="line">                            <span class="keyword">if</span> (loTail == <span class="literal">null</span>)</span><br><span class="line">                                <span class="comment">// 如果没有尾，说明链表为空，链表为空时，头节点指向该元素。</span></span><br><span class="line">                                loHead = e;</span><br><span class="line">                            <span class="keyword">else</span></span><br><span class="line">                                <span class="comment">// 如果有尾，那么链表不为空，把该元素挂到链表的最后。</span></span><br><span class="line">                                loTail.next = e;</span><br><span class="line">                            <span class="comment">// 把尾节点设置为当前元素。</span></span><br><span class="line">                            loTail = e;</span><br><span class="line">                        &#125;</span><br><span class="line">                        <span class="comment">// 原索引+oldCap</span></span><br><span class="line">                        <span class="comment">// 如果与运算结果不为0，说明hash值大于老数组长度（例如hash值为17）。</span></span><br><span class="line">                        <span class="comment">// 此时该元素应该放置到新数组的高位位置上。</span></span><br><span class="line">                        <span class="comment">// 例：老数组长度16，那么新数组长度为32，hash为17的应该放置在数组的第17个位置上，也就是下标为16，那么下标为16已经属于高位了，低位是[0-15]，高位是[16-31]。</span></span><br><span class="line">                        <span class="keyword">else</span> &#123;</span><br><span class="line">                            <span class="keyword">if</span> (hiTail == <span class="literal">null</span>)</span><br><span class="line">                                <span class="comment">// 如果没有尾，说明链表为空，链表为空时，头节点指向该元素。</span></span><br><span class="line">                                hiHead = e;</span><br><span class="line">                            <span class="keyword">else</span></span><br><span class="line">                                <span class="comment">// 如果有尾，那么链表不为空，把该元素挂到链表的最后。</span></span><br><span class="line">                                hiTail.next = e;</span><br><span class="line">                            <span class="comment">// 把尾节点设置为当前元素。</span></span><br><span class="line">                            hiTail = e;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125; <span class="keyword">while</span> ((e = next) != <span class="literal">null</span>);</span><br><span class="line">                    <span class="comment">// 原索引放到bucket里，即低位的元素组成的链表还是放置在原来的位置</span></span><br><span class="line">                    <span class="keyword">if</span> (loTail != <span class="literal">null</span>) &#123;</span><br><span class="line">                        loTail.next = <span class="literal">null</span>;</span><br><span class="line">                        newTab[j] = loHead;</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="comment">// 原索引+oldCap放到bucket里，即高位的元素组成的链表放置的位置只是在原有位置上偏移了老数组的长度个位置。</span></span><br><span class="line">                    <span class="keyword">if</span> (hiTail != <span class="literal">null</span>) &#123;</span><br><span class="line">                        hiTail.next = <span class="literal">null</span>;</span><br><span class="line">                        <span class="comment">// 例1:hash为17在老数组放置在0下标,在新数组放置在16下标;</span></span><br><span class="line">                        <span class="comment">// 例2:hash为18在老数组放置在1下标,在新数组放置在17下标。</span></span><br><span class="line">                        newTab[j + oldCap] = hiHead;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 返回新的位桶数组</span></span><br><span class="line">    <span class="keyword">return</span> newTab;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="2-4-8-treeifyBin方法"><a href="#2-4-8-treeifyBin方法" class="headerlink" title="2.4.8 treeifyBin方法"></a>2.4.8 treeifyBin方法</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 转换为红黑树的操作</span></span><br><span class="line"><span class="comment"> * 参数tab: 元素数组</span></span><br><span class="line"><span class="comment"> * 参数hash: key的hashCode</span></span><br><span class="line"><span class="comment"> * Replaces all linked nodes in bin at index for given hash unless</span></span><br><span class="line"><span class="comment"> * table is too small, in which case resizes instead.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title function_">treeifyBin</span><span class="params">(Node&lt;K,V&gt;[] tab, <span class="type">int</span> hash)</span> &#123;</span><br><span class="line">    <span class="type">int</span> n, index; Node&lt;K,V&gt; e;</span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">     * 如果元素数组为空或者数组长度小于 树结构化的最小限制</span></span><br><span class="line"><span class="comment">     * MIN_TREEIFY_CAPACITY 默认值64，对于这个值可以理解为：</span></span><br><span class="line"><span class="comment">     * 如果元素数组长度小于这个值，没有必要去进行结构转换;</span></span><br><span class="line"><span class="comment">     * 当一个数组位置上集中了多个键值对，那是因为这些key的hash值和数组长度取模之后结果相同.(并不是因为这些</span></span><br><span class="line"><span class="comment">     * key的hash值相同).因为hash值相同的概率不高，所以可以通过扩容的方式，来使得最终这些key的hash值在和新</span></span><br><span class="line"><span class="comment">     * 的数组长度取模之后，拆分到多个数组位置上。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">if</span> (tab == <span class="literal">null</span> || (n = tab.length) &lt; MIN_TREEIFY_CAPACITY)</span><br><span class="line">        <span class="comment">// 如果数组为null或者小于MIN_TREEIFY_CAPACITY=64则进行扩容操作</span></span><br><span class="line">        resize();</span><br><span class="line">    <span class="comment">// 如果元素数组长度已经大于等于了 MIN_TREEIFY_CAPACITY，那么就有必要进行结构转换了。</span></span><br><span class="line">    <span class="comment">// 根据hash值和数组长度进行取模运算后，得到链表的首节点。</span></span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> ((e = tab[index = (n - <span class="number">1</span>) &amp; hash]) != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="comment">// 定义首、尾节点。</span></span><br><span class="line">        TreeNode&lt;K,V&gt; hd = <span class="literal">null</span>, tl = <span class="literal">null</span>;</span><br><span class="line">        <span class="keyword">do</span> &#123;</span><br><span class="line">            <span class="comment">// 将该节点转换为树节点。</span></span><br><span class="line">            TreeNode&lt;K,V&gt; p = replacementTreeNode(e, <span class="literal">null</span>);</span><br><span class="line">            <span class="comment">// 如果尾节点为空，说明还没有根节点。</span></span><br><span class="line">            <span class="keyword">if</span> (tl == <span class="literal">null</span>)</span><br><span class="line">                <span class="comment">// 首节点（根节点）指向当前节点</span></span><br><span class="line">                hd = p;</span><br><span class="line">            <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="comment">// 尾节点不为空，以下两行代码是一个双向链表结构</span></span><br><span class="line">                <span class="comment">// 当前树节点的 前一个节点指向尾节点</span></span><br><span class="line">                p.prev = tl;</span><br><span class="line">                <span class="comment">// 尾节点的 后一个节点指向当前节点</span></span><br><span class="line">                tl.next = p;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 把当前节点设为尾节</span></span><br><span class="line">            tl = p;</span><br><span class="line">            <span class="comment">// 当遍历尾节点为null时候，则结束，否则有节点继续遍历链表</span></span><br><span class="line">        &#125; <span class="keyword">while</span> ((e = e.next) != <span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 到目前为止 也只是把Node对象转换成了TreeNode对象，把单向链表转换成了双向链表</span></span><br><span class="line">        <span class="comment">// 把转换后的双向链表，替换原来位置上的单向链表</span></span><br><span class="line">        <span class="keyword">if</span> ((tab[index] = hd) != <span class="literal">null</span>)</span><br><span class="line">            hd.treeify(tab);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h1 id="3-面试连环炮"><a href="#3-面试连环炮" class="headerlink" title="3. 面试连环炮"></a>3. 面试连环炮</h1><ol>
<li><p>HashMap的基本介绍？</p>
<p>HashMap类是线程不安全且无序的K-V的Map集合容器，底层采用数组+链表+红黑树(JDK8以后)实现。</p>
<p>默认初始化容量为16,默认负载因子是0.75f，当存放在元素时候,计算的hash有冲突(膨胀)时候，进行hash拉链法处理成链表.</p>
<p>在效率权衡之下, 当链表长度大于8时，转化红黑树。当红黑树的节点数小于6时候，又转化为链表。</p>
<p>当容量超过旧容量*负载因子的阈值时，会resize扩容。</p>
</li>
<li><p>为什么是16？为什么必须是2的幂？如果输入值不是2的幂比如10会怎么样？</p>
</li>
<li><p>HashMap的什么时候扩容？扩容机制是什么样的？</p>
</li>
<li><p>HashMap中get和put实现是怎么样的？</p>
</li>
<li><p>为什么不直接将key作为哈希值而是与高16位做异或运算？</p>
</li>
<li><p>为什么引入红黑树？</p>
</li>
</ol>
<h1 id="4-参考文档"><a href="#4-参考文档" class="headerlink" title="4. 参考文档"></a>4. 参考文档</h1><ul>
<li><a target="_blank" rel="noopener" href="https://tech.meituan.com/2016/06/24/java-hashmap.html">Java8系列之重新认识HashMap</a></li>
<li><a target="_blank" rel="noopener" href="https://segmentfault.com/a/1190000003617333">Java7HashMap知识点整理</a></li>
</ul>
</section>
    <!-- Tags START -->
    
      <div class="tags">
        <span>Tags:</span>
        
  <a href="/tags#Java" >
    <span class="tag-code">Java</span>
  </a>

      </div>
    
    <!-- Tags END -->
    <!-- NAV START -->
    
  <div class="nav-container">
    <!-- reverse left and right to put prev and next in a more logic postition -->
    
      <a class="nav-left" href="/2020/05/24/GC%E8%B0%83%E4%BC%98%E5%9F%BA%E7%A1%80%E4%B9%8B%E5%BF%85%E5%A4%87%E7%9F%A5%E8%AF%86/">
        <span class="nav-arrow">← </span>
        
          GC调优基础之必备知识
        
      </a>
    
    
      <a class="nav-right" href="/2020/06/29/%E9%9D%A2%E8%AF%95%E5%AE%98%E4%BD%A0%E7%9C%9F%E7%9A%84%E4%BA%86%E8%A7%A3Java%E5%AF%B9%E8%B1%A1%E5%90%97/">
        
          面试官:你真的了解Java对象吗
        
        <span class="nav-arrow"> →</span>
      </a>
    
  </div>

    <!-- NAV END -->
    <!-- 打赏 START -->
    
      <div class="money-like">
        <div class="reward-btn">
          赏
          <span class="money-code">
            <span class="alipay-code">
              <div class="code-image"></div>
              <b>使用支付宝打赏</b>
            </span>
            <span class="wechat-code">
              <div class="code-image"></div>
              <b>使用微信打赏</b>
            </span>
          </span>
        </div>
        <p class="notice">若你觉得我的文章对你有帮助，欢迎点击上方按钮对我打赏</p>
      </div>
    
    <!-- 打赏 END -->
    <!-- 二维码 START -->
    
      <div class="qrcode">
        <canvas id="share-qrcode"></canvas>
        <p class="notice">扫描二维码，分享此文章</p>
      </div>
    
    <!-- 二维码 END -->
    
      <!-- Utterances START -->
      <div id="utterances"></div>
      <script src="https://utteranc.es/client.js"
        repo="ltyeamin/blogtalks"
        issue-term="pathname"
        theme="github-light"
        crossorigin="anonymous"
        async></script>    
      <!-- Utterances END -->
    
  </article>
  <!-- Article END -->
  <!-- Catalog START -->
  
    <aside class="catalog-container">
  <div class="toc-main">
    <strong class="toc-title">Catalog</strong>
    
      <ol class="toc-nav"><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#1-HashMap%E7%AE%80%E8%BF%B0"><span class="toc-nav-text">1. HashMap简述</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#1-1-%E5%A4%A7%E8%87%B4%E4%BB%8B%E7%BB%8D"><span class="toc-nav-text">1.1 大致介绍</span></a></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#1-2-%E5%BA%95%E5%B1%82%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84"><span class="toc-nav-text">1.2 底层数据结构</span></a></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#1-3-%E7%BB%A7%E6%89%BF%E4%BD%93%E7%B3%BB"><span class="toc-nav-text">1.3 继承体系</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-3-1-Map%E9%A1%B6%E5%B1%82%E6%8E%A5%E5%8F%A3"><span class="toc-nav-text">1.3.1 Map顶层接口</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-3-2-AbstractMap%E6%8A%BD%E8%B1%A1%E7%B1%BB"><span class="toc-nav-text">1.3.2 AbstractMap抽象类</span></a></li></ol></li></ol></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#2-HashMap%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90"><span class="toc-nav-text">2. HashMap源码分析</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#2-1-%E6%88%90%E5%91%98%E5%8F%98%E9%87%8F"><span class="toc-nav-text">2.1 成员变量</span></a></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#2-2-%E6%9E%84%E9%80%A0%E5%99%A8"><span class="toc-nav-text">2.2 构造器</span></a></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#2-3-%E7%BA%A2%E9%BB%91%E6%A0%91%E5%AE%9E%E7%8E%B0"><span class="toc-nav-text">2.3 红黑树实现</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-3-1-Node%E4%BD%8D%E6%A1%B6%E8%8A%82%E7%82%B9"><span class="toc-nav-text">2.3.1 Node位桶节点</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-3-2-TreeNode%E7%BA%A2%E9%BB%91%E6%A0%91"><span class="toc-nav-text">2.3.2 TreeNode红黑树</span></a></li></ol></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#2-4-%E9%87%8D%E8%A6%81%E6%96%B9%E6%B3%95"><span class="toc-nav-text">2.4 重要方法</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-4-1-hash%E6%96%B9%E6%B3%95"><span class="toc-nav-text">2.4.1 hash方法</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-4-2-tableSizeFor%E6%96%B9%E6%B3%95"><span class="toc-nav-text">2.4.2 tableSizeFor方法</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-4-3-size%E6%96%B9%E6%B3%95"><span class="toc-nav-text">2.4.3 size方法</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-4-4-isEmpty%E6%96%B9%E6%B3%95"><span class="toc-nav-text">2.4.4 isEmpty方法</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-4-5-get%E6%96%B9%E6%B3%95"><span class="toc-nav-text">2.4.5 get方法</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-4-6-put%E6%96%B9%E6%B3%95"><span class="toc-nav-text">2.4.6 put方法</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-4-7-resize%E6%96%B9%E6%B3%95"><span class="toc-nav-text">2.4.7 resize方法</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#2-4-8-treeifyBin%E6%96%B9%E6%B3%95"><span class="toc-nav-text">2.4.8 treeifyBin方法</span></a></li></ol></li></ol></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#3-%E9%9D%A2%E8%AF%95%E8%BF%9E%E7%8E%AF%E7%82%AE"><span class="toc-nav-text">3. 面试连环炮</span></a></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#4-%E5%8F%82%E8%80%83%E6%96%87%E6%A1%A3"><span class="toc-nav-text">4. 参考文档</span></a></li></ol>
    
  </div>
</aside>
  
  <!-- Catalog END -->
</main>

<script>
  (function () {
    var url = 'http://example.com/2020/06/18/深入分析HashMap源码/';
    var banner = ''
    if (banner !== '' && banner !== 'undefined' && banner !== 'null') {
      $('#article-banner').css({
        'background-image': 'url(' + banner + ')'
      })
    } else {
      $('#article-banner').geopattern(url)
    }
    $('.header').removeClass('fixed-header')

    // error image
    $(".markdown-content img").on('error', function() {
      $(this).attr('src', '/css/images/error_icon.png')
      $(this).css({
        'cursor': 'default'
      })
    })

    // zoom image
    $(".markdown-content img").on('click', function() {
      var src = $(this).attr('src')
      if (src !== '/css/images/error_icon.png') {
        var imageW = $(this).width()
        var imageH = $(this).height()

        var zoom = ($(window).width() * 0.95 / imageW).toFixed(2)
        zoom = zoom < 1 ? 1 : zoom
        zoom = zoom > 2 ? 2 : zoom
        var transY = (($(window).height() - imageH) / 2).toFixed(2)

        $('body').append('<div class="image-view-wrap"><div class="image-view-inner"><img src="'+ src +'" /></div></div>')
        $('.image-view-wrap').addClass('wrap-active')
        $('.image-view-wrap img').css({
          'width': `${imageW}`,
          'transform': `translate3d(0, ${transY}px, 0) scale3d(${zoom}, ${zoom}, 1)`
        })
        $('html').css('overflow', 'hidden')

        $('.image-view-wrap').on('click', function() {
          $(this).remove()
          $('html').attr('style', '')
        })
      }
    })
  })();
</script>


  <script>
    var qr = new QRious({
      element: document.getElementById('share-qrcode'),
      value: document.location.href
    });
  </script>






    <div class="scroll-top">
  <span class="arrow-icon"></span>
</div>
    <footer class="app-footer">
  <p class="copyright">
    &copy; 2024 | Proudly powered by <a href="https://hexo.io" target="_blank">Hexo</a>
    <br>
    Theme by <a target="_blank" rel="noopener" href="https://github.com/ltyeamin">tong.li</a>
  </p>
</footer>

<script>
  function async(u, c) {
    var d = document, t = 'script',
      o = d.createElement(t),
      s = d.getElementsByTagName(t)[0];
    o.src = u;
    if (c) { o.addEventListener('load', function (e) { c(null, e); }, false); }
    s.parentNode.insertBefore(o, s);
  }
</script>
<script>
  async("https://cdn.staticfile.org/fastclick/1.0.6/fastclick.min.js", function(){
    FastClick.attach(document.body);
  })
</script>

<script>
  var hasLine = 'true';
  async("https://cdn.staticfile.org/highlight.js/9.12.0/highlight.min.js", function(){
    $('figure pre').each(function(i, block) {
      var figure = $(this).parents('figure');
      if (hasLine === 'false') {
        figure.find('.gutter').hide();
      }
      hljs.configure({useBR: true});
      var lang = figure.attr('class').split(' ')[1] || 'code';
      var codeHtml = $(this).html();
      var codeTag = document.createElement('code');
      codeTag.className = lang;
      codeTag.innerHTML = codeHtml;
      $(this).attr('class', '').empty().html(codeTag);
      figure.attr('data-lang', lang.toUpperCase());
      hljs.highlightBlock(block);
    });
  })
</script>
<!-- Baidu Tongji -->



<script src='https://cdn.staticfile.org/mermaid/8.11.2/mermaid.min.js'></script>



<script src="/js/script.js"></script>


  </body>
</html>